DataWhale CV方向 任务二的学习笔记

113 阅读3分钟

这次使用的是深度学习,运用的卷积神经网络,通过学习,发现baseline里使用了CUDA 加速,但是在我安装好torch包之后,发现输出的是False,没有办法,搜了一些方式,但是都不太行。。就更改了一下代码,把使用GPU的部分都删掉了,打算全用CPU来运算,但是还是报错,发现是使用多线程的原因,所以又改成了单线程,就可以正常出结果了。

不过不知道是不是没用GPU和多线程的这个的原因,我得到了一个炸裂的分数。。。

Snipaste_2023-08-21_23-10-13.jpg

我觉得有问题,又运行了一下,重新提交分数就变成了0.74214,看来不是,只能说这个模型可能不是很稳定。。之后再对代码进行修改补充把。。

这次大概就是这样,最近有些忙,时间比较紧,第三次任务希望结果会更好吧。

最后贴一下删掉GPU,并且改为单线程的代码

import os
import glob
import argparse
import pandas as pd
import numpy as np
from tqdm import tqdm

import cv2
from PIL import Image
from sklearn.model_selection import train_test_split, StratifiedKFold, KFold

import torch

# 设置随机数生成器的种子,保证结果可复现
torch.manual_seed(0)

import torchvision.models as models
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
from torch.utils.data.dataset import Dataset

import nibabel as nib
from nibabel.viewers import OrthoSlicer3D

# 获取训练集图像路径
train_path = glob.glob('./脑PET图像分析和疾病预测挑战赛公开数据/Train/*/*')
# 获取测试集图像路径
test_path = glob.glob('./脑PET图像分析和疾病预测挑战赛公开数据/Test/*')
# 打乱训练集路径列表
np.random.shuffle(train_path)
# 打乱测试集路径列表
np.random.shuffle(test_path)
# 用于缓存图像数据,避免重复读取
DATA_CACHE = {}

# 自定义数据集类,用于处理图像数据集
class XunFeiDataset(Dataset):
    def __init__(self, img_path, transform=None):
        self.img_path = img_path
        if transform is not None:
            self.transform = transform
        else:
            self.transform = None

    def __getitem__(self, index):
        if self.img_path[index] in DATA_CACHE:
            img = DATA_CACHE[self.img_path[index]]
        else:
            img = nib.load(self.img_path[index])
            img = img.dataobj[:, :, :, 0]
            DATA_CACHE[self.img_path[index]] = img

        idx = np.random.choice(range(img.shape[-1]), 50)
        img = img[:, :, idx]
        img = img.astype(np.float32)

        if self.transform is not None:
            img = self.transform(image=img)['image']

        img = img.transpose([2, 0, 1])
        return img, torch.from_numpy(np.array(int('NC' in self.img_path[index])))

    def __len__(self):
        return len(self.img_path)

import albumentations as A

# 对训练数据集进行数据预处理
train_loader = torch.utils.data.DataLoader(
    XunFeiDataset(
        train_path[:-10],  # 不包括最后10个图像的路径
        A.Compose([
            A.RandomRotate90(),  # 随机旋转90度
            A.RandomCrop(120, 120),  # 随机裁剪为120×120大小
            A.HorizontalFlip(p=0.5),  # 水平翻转概率为0.5
            A.RandomContrast(p=0.5),  # 随机对比度调整概率为0.5
            A.RandomBrightnessContrast(p=0.5),  # 随机亮度对比度调整概率为0.5
        ])
    ), batch_size=2,  # 批大小为2
    shuffle=True  # 在每个训练周期开始时打乱数据顺序
)

# 对验证数据集进行数据预处理
val_loader = torch.utils.data.DataLoader(
    XunFeiDataset(train_path[-10:],
                  A.Compose([
                      A.RandomCrop(120, 120),
                  ])
                  ), batch_size=2, shuffle=False
)

# 对测试数据集进行数据预处理
test_loader = torch.utils.data.DataLoader(
    XunFeiDataset(test_path,
                  A.Compose([
                      A.RandomCrop(128, 128),
                      A.HorizontalFlip(p=0.5),  # 水平翻转概率为0.5
                      A.RandomContrast(p=0.5),  # 随机对比度调整概率为0.5
                  ])
                  ), batch_size=2, shuffle=False
)

# 定义自定义的XunFeiNet模型类
class XunFeiNet(nn.Module):
    def __init__(self):
        super(XunFeiNet, self).__init__()

        model = models.resnet18(True)
        model.conv1 = torch.nn.Conv2d(50, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
        model.avgpool = nn.AdaptiveAvgPool2d(1)
        model.fc = nn.Linear(512, 2)
        self.resnet = model

    def forward(self, img):
        out = self.resnet(img)
        return out

model = XunFeiNet()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.AdamW(model.parameters(), 0.001)

# 训练函数
def train(train_loader, model, criterion, optimizer):
    model.train()
    train_loss = 0.0
    for i, (input, target) in enumerate(train_loader):
        output = model(input)
        loss = criterion(output, target.long())
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if i % 20 == 0:
            print(loss.item())
        train_loss += loss.item()
    return train_loss / len(train_loader)

# 验证函数
def validate(val_loader, model, criterion):
    model.eval()
    val_acc = 0.0
    with torch.no_grad():
        for i, (input, target) in enumerate(val_loader):
            output = model(input)
            loss = criterion(output, target.long())
            val_acc += (output.argmax(1) == target).sum().item()
    return val_acc / len(val_loader.dataset)

# 训练循环
for _ in range(3):
    train_loss = train(train_loader, model, criterion, optimizer)
    val_acc = validate(val_loader, model, criterion)
    train_acc = validate(train_loader, model, criterion)
    print(f'Epoch {_ + 1}: Train Loss: {train_loss}, Train Acc: {train_acc}, Val Acc: {val_acc}')

# 预测函数
def predict(test_loader, model, criterion):
    model.eval()
    val_acc = 0.0
    test_pred = []
    with torch.no_grad():
        for i, (input, target) in enumerate(test_loader):
            output = model(input)
            test_pred.append(output.data.cpu().numpy())
    return np.vstack(test_pred)

pred = None

# 对测试集进行预测
for _ in range(10):
    if pred is None:
        pred = predict(test_loader, model, criterion)
    else:
        pred += predict(test_loader, model, criterion)

# 生成提交文件
submit = pd.DataFrame(
    {
        'uuid': [int(x.split('\\')[-1][:-4]) for x in test_path],
        'label': pred.argmax(1)
    })
submit['label'] = submit['label'].map({1: 'NC', 0: 'MCI'})
submit = submit.sort_values(by='uuid')
submit.to_csv('submit2.csv', index=None)