第60步 深度学习图像识别:误判病例分析(Pytorch)

news2024/9/28 5:30:26

基于WIN10的64位系统演示

一、写在前面

上期内容基于Tensorflow环境做了误判病例分析(传送门),考虑到不少模型在Tensorflow环境没有迁移学习的预训练模型,因此有必要在Pytorch环境也搞搞误判病例分析。

本期以SqueezeNet模型为例,因为它建模速度快。

同样,基于GPT-4辅助编程,后续会分享改写过程。

二、误判病例分析实战

继续使用胸片的数据集:肺结核病人和健康人的胸片的识别。其中,肺结核病人700张,健康人900张,分别存入单独的文件夹中。

(a)直接分享代码

######################################导入包###################################
# 导入必要的包
import copy
import torch
import torchvision
import torchvision.transforms as transforms
from torchvision import models
from torch.utils.data import DataLoader
from torch import optim, nn
from torch.optim import lr_scheduler
import os
import matplotlib.pyplot as plt
import warnings
import numpy as np

warnings.filterwarnings("ignore")
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 设置GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")


################################导入数据集#####################################
import torch
from torchvision import datasets, transforms
from torch.nn.functional import softmax
import os
from PIL import Image
import pandas as pd
import torch.nn as nn
import timm
from torch.optim import lr_scheduler

# 自定义的数据集类
class ImageFolderWithPaths(datasets.ImageFolder):
    def __getitem__(self, index):
        original_tuple = super(ImageFolderWithPaths, self).__getitem__(index)
        path = self.imgs[index][0]
        tuple_with_path = (original_tuple + (path,))
        return tuple_with_path

# 数据集路径
data_dir = "./MTB"

# 图像的大小
img_height = 256
img_width = 256

# 数据预处理
data_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(img_height),
        transforms.RandomHorizontalFlip(),
        transforms.RandomVerticalFlip(),
        transforms.RandomRotation(0.2),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.Resize((img_height, img_width)),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}

# 加载数据集
full_dataset = ImageFolderWithPaths(data_dir, transform=data_transforms['train'])

# 获取数据集的大小
full_size = len(full_dataset)
train_size = int(0.8 * full_size)  # 假设训练集占70%
val_size = full_size - train_size  # 验证集的大小

# 随机分割数据集
torch.manual_seed(0)  # 设置随机种子以确保结果可重复
train_dataset, val_dataset = torch.utils.data.random_split(full_dataset, [train_size, val_size])

# 应用数据增强到训练集和验证集
train_dataset.dataset.transform = data_transforms['train']
val_dataset.dataset.transform = data_transforms['val']

# 创建数据加载器
batch_size = 32
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=0)
val_dataloader = torch.utils.data.DataLoader(val_dataset, batch_size=batch_size, shuffle=True, num_workers=0)


dataloaders = {'train': train_dataloader, 'val': val_dataloader}
dataset_sizes = {'train': len(train_dataset), 'val': len(val_dataset)}
class_names = full_dataset.classes

# 获取数据集的类别
class_names = full_dataset.classes

# 保存预测结果的列表
results = []

###############################定义SqueezeNet模型################################
# 定义SqueezeNet模型
model = models.squeezenet1_1(pretrained=True)  # 这里以SqueezeNet 1.1版本为例
num_ftrs = model.classifier[1].in_channels

# 根据分类任务修改最后一层
model.classifier[1] = nn.Conv2d(num_ftrs, len(class_names), kernel_size=(1,1))

# 修改模型最后的输出层为我们需要的类别数
model.num_classes = len(class_names)

model = model.to(device)

# 打印模型摘要
print(model)


#############################编译模型#########################################
# 定义损失函数
criterion = nn.CrossEntropyLoss()

# 定义优化器
optimizer = torch.optim.Adam(model.parameters())

# 定义学习率调度器
exp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)

# 开始训练模型
num_epochs = 5

# 初始化记录器
train_loss_history = []
train_acc_history = []
val_loss_history = []
val_acc_history = []

for epoch in range(num_epochs):
    print('Epoch {}/{}'.format(epoch, num_epochs - 1))
    print('-' * 10)

    # 每个epoch都有一个训练和验证阶段
    for phase in ['train', 'val']:
        if phase == 'train':
            model.train()  # 设置模型为训练模式
        else:
            model.eval()   # 设置模型为评估模式

        running_loss = 0.0
        running_corrects = 0

        # 遍历数据
        for inputs, labels, paths in dataloaders[phase]:
            inputs = inputs.to(device)
            labels = labels.to(device)

            # 零参数梯度
            optimizer.zero_grad()

            # 前向
            with torch.set_grad_enabled(phase == 'train'):
                outputs = model(inputs)
                _, preds = torch.max(outputs, 1)
                loss = criterion(outputs, labels)

                # 只在训练模式下进行反向和优化
                if phase == 'train':
                    loss.backward()
                    optimizer.step()

            # 统计
            running_loss += loss.item() * inputs.size(0)
            running_corrects += torch.sum(preds == labels.data)

        epoch_loss = running_loss / dataset_sizes[phase]
        epoch_acc = (running_corrects.double() / dataset_sizes[phase]).item()

        # 记录每个epoch的loss和accuracy
        if phase == 'train':
            train_loss_history.append(epoch_loss)
            train_acc_history.append(epoch_acc)
        else:
            val_loss_history.append(epoch_loss)
            val_acc_history.append(epoch_acc)

        print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))

    print()

# 保存模型
torch.save(model.state_dict(), 'SqueezeNet_model-1.pth')

# 加载最佳模型权重
#model.load_state_dict(best_model_wts)
#torch.save(model, 'shufflenet_best_model.pth')
#print("The trained model has been saved.")
###########################误判病例分析#################################
# 导入 os 库
import os

# 使用模型对训练集和验证集中的所有图片进行预测,并保存预测结果
for phase in ['train', 'val']:
    for inputs, labels, paths in dataloaders[phase]:  # 在这里添加 paths
        inputs = inputs.to(device)
        labels = labels.to(device)

        # 使用模型对这一批图片进行预测
        outputs = model(inputs)
        probabilities = softmax(outputs, dim=1)
        _, predictions = torch.max(outputs, 1)

        # 遍历这一批图片
        for i, path in enumerate(paths):  # 在这里添加 path 和 enumerate 函数
            # 获取图片的名称、标签、预测值和概率
            image_name = os.path.basename(path)  # 使用 os.path.basename 函数获取图片名称
            original_label = class_names[labels[i]]
            prediction = predictions[i]
            probability = probabilities[i]

            # 根据预测结果和真实标签,判定图片所属的组别
            group = None
            if original_label == "Tuberculosis" and probability[1] >= 0.5:
                group = "A"
            elif original_label == "Normal" and probability[1] < 0.5:
                group = "B"
            elif original_label == "Normal" and probability[1] >= 0.5:
                group = "C"
            elif original_label == "Tuberculosis" and probability[1] < 0.5:
                group = "D"

            # 将结果添加到结果列表中
            results.append({
                "原始图片的名称": image_name,
                "属于训练集还是验证集": phase,
                "预测为Tuberculosis的概率值": probability[1].item(),
                "判定的组别": group
            })

# 将结果保存为Pandas DataFrame,然后保存到csv文件
result_df = pd.DataFrame(results)
result_df.to_csv("result-2.csv", index=False)

跟Tensorflow改写的类似,主要有两处变化:

(1)导入数据集部分:而在误判病例分析中,我们需要知道每一张图片的名称、被预测的结果等详细信息因此需要加载图片路径和图片名称的信息。

(2)误判病例分析部分:也就是需要知道哪些预测正确,哪些预测错误。

(b)调教GPT-4的过程

(b1)咒语:请根据{代码1},改写和续写《代码2》。代码1:{也就是之前用tensorflow写的误判病例分析部分};代码2:《也就是修改之前的SqueezeNet模型建模代码》

还是列出来吧:

代码1:

# 训练模型后,现在使用模型对所有图片进行预测,并保存预测结果到csv文件中
import pandas as pd

# 保存预测结果的dataframe
result_df = pd.DataFrame(columns=["原始图片的名称", "属于训练集还是验证集", "预测为Tuberculosis的概率值", "判定的组别"])

# 对训练集和验证集中的每一批图片进行预测
for dataset, dataset_name in zip([train_ds_with_filenames, val_ds_with_filenames], ["训练集", "验证集"]):
    for images, labels, paths in dataset:
        # 使用模型对这一批图片进行预测
        probabilities = model.predict(images)
        predictions = tf.math.argmax(probabilities, axis=-1)

        # 遍历这一批图片
        for path, label, prediction, probability in zip(paths, labels, predictions, probabilities):
            # 获取图片名称和真实标签
            image_name = path.numpy().decode("utf-8").split('/')[-1]
            original_label = class_names[label]

            # 根据预测结果和真实标签,判定图片所属的组别
            group = None
            if original_label == "Tuberculosis" and probability[1] >= 0.5:
                group = "A"
            elif original_label == "Normal" and probability[1] < 0.5:
                group = "B"
            elif original_label == "Normal" and probability[1] >= 0.5:
                group = "C"
            elif original_label == "Tuberculosis" and probability[1] < 0.5:
                group = "D"

            # 将结果添加到dataframe中
            result_df = result_df.append({
                "原始图片的名称": image_name,
                "属于训练集还是验证集": dataset_name,
                "预测为Tuberculosis的概率值": probability[1],
                "判定的组别": group
            }, ignore_index=True)

# 保存结果到csv文件
result_df.to_csv("result.csv", index=False)

代码2:

######################################导入包###################################
# 导入必要的包
import copy
import torch
import torchvision
import torchvision.transforms as transforms
from torchvision import models
from torch.utils.data import DataLoader
from torch import optim, nn
from torch.optim import lr_scheduler
import os
import matplotlib.pyplot as plt
import warnings
import numpy as np

warnings.filterwarnings("ignore")
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 设置GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")


################################导入数据集#####################################
import torch
from torchvision import datasets, transforms
import os

# 数据集路径
data_dir = "./MTB"

# 图像的大小
img_height = 256
img_width = 256

# 数据预处理
data_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(img_height),
        transforms.RandomHorizontalFlip(),
        transforms.RandomVerticalFlip(),
        transforms.RandomRotation(0.2),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.Resize((img_height, img_width)),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}

# 加载数据集
full_dataset = datasets.ImageFolder(data_dir)

# 获取数据集的大小
full_size = len(full_dataset)
train_size = int(0.7 * full_size)  # 假设训练集占80%
val_size = full_size - train_size  # 验证集的大小

# 随机分割数据集
torch.manual_seed(0)  # 设置随机种子以确保结果可重复
train_dataset, val_dataset = torch.utils.data.random_split(full_dataset, [train_size, val_size])

# 将数据增强应用到训练集
train_dataset.dataset.transform = data_transforms['train']

# 创建数据加载器
batch_size = 32
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=4)
val_dataloader = torch.utils.data.DataLoader(val_dataset, batch_size=batch_size, shuffle=True, num_workers=4)

dataloaders = {'train': train_dataloader, 'val': val_dataloader}
dataset_sizes = {'train': len(train_dataset), 'val': len(val_dataset)}
class_names = full_dataset.classes


###############################定义TNT模型################################
# 导入必要的库
import torch.nn as nn
import timm

# 定义Bottleneck Transformer模型
model = timm.create_model('botnet26t_256', pretrained=True)  # 你可以选择适合你需求的BotNet版本
num_ftrs = model.feature_info[-1]['num_chs']

# 根据分类任务修改最后一层
model.head.fc = nn.Linear(num_ftrs, len(class_names))

# 将模型移至指定设备
model = model.to(device)

# 打印模型摘要
print(model)


#############################编译模型#########################################
# 定义损失函数
criterion = nn.CrossEntropyLoss()

# 定义优化器
optimizer = optim.Adam(model.parameters())

# 定义学习率调度器
exp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)

# 开始训练模型
num_epochs = 20

# 初始化记录器
train_loss_history = []
train_acc_history = []
val_loss_history = []
val_acc_history = []

for epoch in range(num_epochs):
    print('Epoch {}/{}'.format(epoch, num_epochs - 1))
    print('-' * 10)

    # 每个epoch都有一个训练和验证阶段
    for phase in ['train', 'val']:
        if phase == 'train':
            model.train()  # 设置模型为训练模式
        else:
            model.eval()   # 设置模型为评估模式

        running_loss = 0.0
        running_corrects = 0

        # 遍历数据
        for inputs, labels in dataloaders[phase]:
            inputs = inputs.to(device)
            labels = labels.to(device)

            # 零参数梯度
            optimizer.zero_grad()

            # 前向
            with torch.set_grad_enabled(phase == 'train'):
                outputs = model(inputs)
                _, preds = torch.max(outputs, 1)
                loss = criterion(outputs, labels)

                # 只在训练模式下进行反向和优化
                if phase == 'train':
                    loss.backward()
                    optimizer.step()

            # 统计
            running_loss += loss.item() * inputs.size(0)
            running_corrects += torch.sum(preds == labels.data)

        epoch_loss = running_loss / dataset_sizes[phase]
        epoch_acc = (running_corrects.double() / dataset_sizes[phase]).item()

        # 记录每个epoch的loss和accuracy
        if phase == 'train':
            train_loss_history.append(epoch_loss)
            train_acc_history.append(epoch_acc)
        else:
            val_loss_history.append(epoch_loss)
            val_acc_history.append(epoch_acc)

        print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))

    print()

# 保存模型
torch.save(model.state_dict(), 'tnt_dit_model.pth')

GPT-4回复:

代码2的改写版本如下:

首先,我们需要为PyTorch添加类别名称,以便我们在生成结果时可以进行映射,然后创建一个列表来存储预测结果。

################################导入数据集#####################################
...
# 获取数据集的类别
class_names = full_dataset.classes
# 保存预测结果的列表
results = []

接着,我们在进行预测时,为了获取每个样本的概率,我们需要使用torch.nn.functional.softmax()函数,同时还需要将预测值与0.5比较,以判定组别。最后,我们使用Pandas将预测结果保存为CSV文件。

import pandas as pd
from torch.nn.functional import softmax

# 使用模型对训练集和验证集中的所有图片进行预测,并保存预测结果
for phase in ['train', 'val']:
    for inputs, labels in dataloaders[phase]:
        inputs = inputs.to(device)
        labels = labels.to(device)

        # 使用模型对这一批图片进行预测
        outputs = model(inputs)
        probabilities = softmax(outputs, dim=1)
        _, predictions = torch.max(outputs, 1)

        # 遍历这一批图片
        for i in range(inputs.size(0)):
            # 获取图片的名称、标签、预测值和概率
            image_name = dataloaders[phase].dataset.dataset.samples[i][0].split('/')[-1]
            original_label = class_names[labels[i]]
            prediction = predictions[i]
            probability = probabilities[i]

            # 根据预测结果和真实标签,判定图片所属的组别
            group = None
            if original_label == "Tuberculosis" and probability[1] >= 0.5:
                group = "A"
            elif original_label == "Normal" and probability[1] < 0.5:
                group = "B"
            elif original_label == "Normal" and probability[1] >= 0.5:
                group = "C"
            elif original_label == "Tuberculosis" and probability[1] < 0.5:
                group = "D"

            # 将结果添加到结果列表中
            results.append({
                "原始图片的名称": image_name,
                "属于训练集还是验证集": phase,
                "预测为Tuberculosis的概率值": probability[1].item(),
                "判定的组别": group
            })

# 将结果保存为Pandas DataFrame,然后保存到csv文件
result_df = pd.DataFrame(results)
result_df.to_csv("result.csv", index=False)

我们看看“result.csv”文件是否符合我们的要求:

 

问题很明显,分组全是“Normal”!!!

(b2)咒语:为什么输出的“原始图片的名车”全部是“MTB\Normal\”,完全没有“Tuberculosis”?

GPT-4回复:

在PyTorch中,当我们使用torchvision的datasets.ImageFolder载入数据时,数据被按照文件夹的顺序进行排序,所以获取图片名称时,我们只是在循环中按顺序获取了数据集中的图片路径。这可能会在对验证集进行预测时出现问题,因为我们使用了random_split函数对数据进行了随机划分,而获取图片路径的方式并未考虑到这个随机性。

为了解决这个问题,你可以试试将图片路径也保存在数据加载器中。在这里,我假设你的训练集和验证集是以文件夹的形式存储的,每个文件夹的名字就是类别的名称。以下是一个简单的自定义数据集类,它可以在加载数据的同时获取每个图片的路径:

from torch.utils.data import Dataset
from PIL import Image

class ImageFolderWithPaths(Dataset):
    def __init__(self, image_folder, transform=None):
        self.image_folder = image_folder
        self.transform = transform
        self.image_paths = list(map(lambda x: x[0], image_folder.imgs))

    def __getitem__(self, index):
        original_tuple = self.image_folder.imgs[index]
        path = original_tuple[0]
        image = Image.open(path).convert("RGB")
        if self.transform is not None:
            image = self.transform(image)
        
        return (image, original_tuple[1], path)

    def __len__(self):
        return len(self.image_folder.imgs)

你可以这样使用这个数据集类:

# 创建原始的ImageFolder数据集
original_dataset = datasets.ImageFolder(data_dir, transform=data_transforms['train'])

# 使用我们的自定义数据集类,获取图片路径
full_dataset = ImageFolderWithPaths(original_dataset, transform=data_transforms['train'])

# 现在,你的数据加载器在每次迭代时都会返回图片、标签和图片路径
for images, labels, paths in dataloader:
    ...

看得懂怎么改写代码不?看不懂也不要紧,继续:

(b3)咒语:帮我在这个代码上改写和更新,并展示所有代码:{复制代码}

GPT-4回复:

import torch
from torchvision import datasets, transforms
from torch.nn.functional import softmax
import os
from PIL import Image
import pandas as pd
import torch.nn as nn
import timm
from torch.optim import lr_scheduler

# 自定义的数据集类
class ImageFolderWithPaths(datasets.ImageFolder):
    def __getitem__(self, index):
        original_tuple = super(ImageFolderWithPaths, self).__getitem__(index)
        path = self.imgs[index][0]
        tuple_with_path = (original_tuple + (path,))
        return tuple_with_path

# 数据集路径
data_dir = "./MTB"

# 图像的大小
img_height = 256
img_width = 256

# 数据预处理
data_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(img_height),
        transforms.RandomHorizontalFlip(),
        transforms.RandomVerticalFlip(),
        transforms.RandomRotation(0.2),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.Resize((img_height, img_width)),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}

# 加载数据集
full_dataset = ImageFolderWithPaths(data_dir, transform=data_transforms['train'])

# 获取数据集的大小
full_size = len(full_dataset)
train_size = int(0.7 * full_size)  # 假设训练集占70%
val_size = full_size - train_size  # 验证集的大小

# 随机分割数据集
torch.manual_seed(0)  # 设置随机种子以确保结果可重复
train_dataset, val_dataset = torch.utils.data.random_split(full_dataset, [train_size, val_size])

# 应用数据增强到训练集和验证集
train_dataset.dataset.transform = data_transforms['train']
val_dataset.dataset.transform = data_transforms['val']

# 创建数据加载器
batch_size = 32
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=4)
val_dataloader = torch.utils.data.DataLoader(val_dataset, batch_size=batch_size, shuffle=True, num_workers=4)

dataloaders = {'train': train_dataloader, 'val': val_dataloader}
dataset_sizes = {'train': len(train_dataset), 'val': len(val_dataset)}
class_names = full_dataset.classes

# 获取数据集的类别
class_names = full_dataset.classes

# 保存预测结果的列表
results = []

###############################定义TNT模型################################
# 定义Bottleneck Transformer模型
model = timm.create_model('botnet26t_256', pretrained=True)  # 你可以选择适合你需求的BotNet版本
num_ftrs = model.feature_info[-1]['num_chs']

# 根据分类任务修改最后一层
model.head.fc = nn.Linear(num_ftrs, len(class_names))

# 将模型移至指定设备
model = model.to(device)

# 打印模型摘要
print(model)


#############################编译模型#########################################
# 定义损失函数
criterion = nn.CrossEntropyLoss()

# 定义优化器
optimizer = torch.optim.Adam(model.parameters())

# 定义学习率调度器
exp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)

# 开始训练模型
num_epochs = 4

# 初始化记录器
train_loss_history = []
train_acc_history = []
val_loss_history = []
val_acc_history = []

for epoch in range(num_epochs):
    print('Epoch {}/{}'.format(epoch, num_epochs - 1))
    print('-' * 10)

    # 每个epoch都有一个训练和验证阶段
    for phase in ['train', 'val']:
        if phase == 'train':
            model.train()  # 设置模型为训练模式
        else:
            model.eval()   # 设置模型为评估模式

        running_loss = 0.0
        running_corrects = 0

        # 遍历数据
        for inputs, labels in dataloaders[phase]:
            inputs = inputs.to(device)
            labels = labels.to(device)

            # 零参数梯度
            optimizer.zero_grad()

            # 前向
            with torch.set_grad_enabled(phase == 'train'):
                outputs = model(inputs)
                _, preds = torch.max(outputs, 1)
                loss = criterion(outputs, labels)

                # 只在训练模式下进行反向和优化
                if phase == 'train':
                    loss.backward()
                    optimizer.step()

            # 统计
            running_loss += loss.item() * inputs.size(0)
            running_corrects += torch.sum(preds == labels.data)

        epoch_loss = running_loss / dataset_sizes[phase]
        epoch_acc = (running_corrects.double() / dataset_sizes[phase]).item()

        # 记录每个epoch的loss和accuracy
        if phase == 'train':
            train_loss_history.append(epoch_loss)
            train_acc_history.append(epoch_acc)
        else:
            val_loss_history.append(epoch_loss)
            val_acc_history.append(epoch_acc)

        print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))

    print()

# 保存模型
torch.save(model.state_dict(), 'bonet_dit_model-1.pth')

# 加载最佳模型权重
#model.load_state_dict(best_model_wts)
#torch.save(model, 'shufflenet_best_model.pth')
#print("The trained model has been saved.")
###########################误判病例分析#################################
# 使用模型对训练集和验证集中的所有图片进行预测,并保存预测结果
for phase in ['train', 'val']:
    for inputs, labels, paths in dataloaders[phase]:
        inputs = inputs.to(device)
        labels = labels.to(device)

        # 使用模型对这一批图片进行预测
        outputs = model(inputs)
        probabilities = softmax(outputs, dim=1)
        _, predictions = torch.max(outputs, 1)

        # 遍历这一批图片
        for i in range(inputs.size(0)):
            # 获取图片的名称、标签、预测值和概率
            image_name = os.path.basename(paths[i])
            original_label = class_names[labels[i]]
            prediction = predictions[i]
            probability = probabilities[i]

            # 根据预测结果和真实标签,判定图片所属的组别
            if original_label == class_names[prediction]:
                group = 'correct'  # 正确预测的图片
            else:
                group = 'misclassified'  # 错误预测的图片

            # 将结果保存为字典
            result = {
                'image': image_name,
                'label': original_label,
                'prediction': class_names[prediction],
                'probability': probability,
                'group': group
            }

            # 将字典添加到结果列表中
            results.append(result)

# 将结果列表保存为数据框,并输出为csv文件
results_df = pd.DataFrame(results)
results_df.to_csv('classification_results.csv', index=False)

运行,报错,哈哈哈:

(b4)咒语:报错:Traceback (most recent call last): File "<string>", line 1, in <module>File "C:\ProgramData\Anaconda3\envs\Pytorch\lib\multiprocessing\spawn.py", line 116, in spawn_main exitcode = _main(fd, parent_sentinel)

  File "C:\ProgramData\Anaconda3\envs\Pytorch\lib\multiprocessing\spawn.py", line 126, in _main self = reduction.pickle.load(from_parent)

AttributeError: Can't get attribute 'ImageFolderWithPaths' on <module '__main__' (built-in)>

GPT-4回复:

 

 继续报错,继续问:Traceback (most recent call last):

  File "C:\Users\Administrator\AppData\Local\Temp\ipykernel_19344\1832509689.py", line 146, in <cell line: 131>

    for inputs, labels in dataloaders[phase]:

ValueError: too many values to unpack (expected 2)

GPT-4回答:

 

最后能运行了,又回到(b2)的问题:为什么输出的“原始图片的名称”全部是“MTB\Normal\”,完全没有“Tuberculosis”???一脸蒙蔽,无奈我又问了TA一次。

(b4)咒语:为什么输出的“原始图片的名车”还全部是“MTB\Normal\”,完全没有“Tuberculosis”????请显示完整的代码以解决这个问题。

GPT-4这回给出正确答案:

# 导入 os 库
import os

# 使用模型对训练集和验证集中的所有图片进行预测,并保存预测结果
for phase in ['train', 'val']:
    for inputs, labels, paths in dataloaders[phase]:  # 在这里添加 paths
        inputs = inputs.to(device)
        labels = labels.to(device)

        # 使用模型对这一批图片进行预测
        outputs = model(inputs)
        probabilities = softmax(outputs, dim=1)
        _, predictions = torch.max(outputs, 1)

        # 遍历这一批图片
        for i, path in enumerate(paths):  # 在这里添加 path 和 enumerate 函数
            # 获取图片的名称、标签、预测值和概率
            image_name = os.path.basename(path)  # 使用 os.path.basename 函数获取图片名称
            original_label = class_names[labels[i]]
            prediction = predictions[i]
            probability = probabilities[i]

            # 根据预测结果和真实标签,判定图片所属的组别
            group = None
            if original_label == "Tuberculosis" and probability[1] >= 0.5:
                group = "A"
            elif original_label == "Normal" and probability[1] < 0.5:
                group = "B"
            elif original_label == "Normal" and probability[1] >= 0.5:
                group = "C"
            elif original_label == "Tuberculosis" and probability[1] < 0.5:
                group = "D"

            # 将结果添加到结果列表中
            results.append({
                "原始图片的名称": image_name,
                "属于训练集还是验证集": phase,
                "预测为Tuberculosis的概率值": probability[1].item(),
                "判定的组别": group
            })

# 将结果保存为Pandas DataFrame,然后保存到csv文件
result_df = pd.DataFrame(results)
result_df.to_csv("result-2.csv", index=False)

总结:现在来看,改写过程中出问题大概率是图片的路径提取中出了问题。核心咒语还是一样的:{以0.5为阈值,因此可以样本分为三份:(a)本来就是Tuberculosis的图片,预测为Tuberculosis的概率值大于等于0.5,则说明预测正确,判定为A组;(b)本来就是Normal的图片,预测为Tuberculosis的概率值小于0.5,则说明预测正确,判定为B组;(c)本来就是Normal的图片,预测为Tuberculosis的概率值大于等于0.5,则说明预测错误,判定为C组;(d)本来就是Tuberculosis的图片,预测为Tuberculosis的概率值小于0.5,则说明预测正确,判定为D组;},剩余的就跟GPT-4对线,出了问题及时且准确的进行反馈,这很重要!!!

三、输出结果

 有了这个表,又可以水不少图了。

四、数据

链接:https://pan.baidu.com/s/15vSVhz1rQBtqNkNp2GQyVw?pwd=x3jf

提取码:x3jf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/921148.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java不用加减乘除做加法(图文详解)

目录 1.题目描述 2.题解 分析 具体实现 1.题目描述 写一个函数&#xff0c;求两个整数之和&#xff0c;要求在函数体内不得使用、-、*、/四则运算符号。 示例 输入&#xff1a;1 2 输出&#xff1a;3 2.题解 分析 不能使用加减乘除四则运算符&#xff0c;那我们只能考虑…

论文笔记:从不平衡数据流中学习的综述: 分类、挑战、实证研究和可重复的实验框架

0 摘要 论文&#xff1a;A survey on learning from imbalanced data streams: taxonomy, challenges, empirical study, and reproducible experimental framework 发表&#xff1a;2023年发表在Machine Learning上。 源代码&#xff1a;https://github.com/canoalberto/imba…

多环境开发

多环境 1、多环境开发&#xff08;YAML版&#xff09; 小结&#xff1a; 多环境开发需要设置若干种常用环境&#xff0c;例如开发、生产、测试环境yaml格式中设置多环境使用—区分环境设置边界每种环境的区别在于加载的配置属性不同启用某种环境时需要指定启动时使用该环境 …

跨境电商儿童沙画办理EN71测试标准

儿童沙画就是小孩子玩的那种用彩色沙子或者彩色墨水&#xff0c;在有图形轮廓的纸片上去绘画&#xff0c;可以按照儿童沙画底板上的人物轮廓线条&#xff0c;动物线条&#xff0c;风景线条&#xff0c;动漫线条&#xff0c;去添加自己喜欢的颜色&#xff0c;让单调的线条变成自…

请不要将数据中台做成BI!

近年来&#xff0c;随着数据驱动决策的重要性日益凸显&#xff0c;数据管理的概念也不断演进。数据中台作为一种新兴的数据管理模式&#xff0c;旨在集中组织和整合数据资源&#xff0c;为企业提供更高效、更智能的数据支持。然而&#xff0c;有时候在构建数据中台的过程中&…

C语言入门 Day_9 条件判断

目录 前言&#xff1a; 1.if判断 2.else判断 3.易错点 4.思维导图 前言&#xff1a; 我们知道比较运算和逻辑运算都会得到一个布尔型的数据&#xff0c;要么为真&#xff08;true&#xff09;&#xff0c;要么为假&#xff08;false&#xff09;。 今天我们来学习真和假在…

【性能优化】使用Perfetto定位应用启动性能的瓶颈

Android应用启动优化相关的文章已经有很多人都写过了&#xff0c;但是主要都是聚焦在&#xff0c;为了启动性能都做了哪些改动上&#xff0c;少见有文章会说应该如何分析、识别应用的启动性能。 本篇文章将会结合我个人对Perfetto的实际使用经历&#xff0c;讲解车载应用的启动…

Python“牵手”当当网商品详情API接口运用场景及功能介绍,当当网API接口申请指南

当当网是全球知名的综合性网上购物商城&#xff0c;由国内著名出版机构科文公司、美国老虎基金、美国IDG集团、卢森堡剑桥集团、亚洲创业投资基金&#xff08;原名软银中国创业基金&#xff09;共同投资成立。当当网是北京当当网信息技术有限公司营运的一家中文购物网站&#x…

【校招VIP】产品行测考点之图的推理和分析

考点介绍&#xff1a; 大厂产品校招笔试里经常会出现行测的考察&#xff0c;而图的推理是行测里面稍微有难度的一部分。因为时间有限&#xff0c;很多同学因为没有解题思路而丢分。 『产品行测考点之图的推理和分析』相关题目及解析内容可点击文章末尾链接查看&#xff01; 一…

【Unity小技巧】最简单的UI设置适配方案,萌新必看

文章目录 前言导入素材开始一、页面适配方案二、侧边栏适配方法一方法二 参考完结 前言 这期来讲一个简单的UI设计方案&#xff0c;很多同学可能搞不懂锚点、轴心这些概念&#xff0c;导致做好的UI在别人的设备上&#xff0c;乱跑或者是重叠&#xff0c;或者是参加游戏老发时间…

10-案例: 注册登录

项目思路: 1. 首页展示 将数据传递给前端模板渲染 2. 注册用户 接收前端传递的数据,保存后,重定向到首页 3. 删除用户 接收前端传递的用户名,进行删除 4. 修改用户 接收前端传递的数据,老名字进行判断,新数据修改数据 项目结构: 构建蓝图: (1). apps / user / model.py 增…

知道吗?微软将Python集成到Excel中,国产软件“抄作业”了

Excel集成Python 众所周知哦&#xff0c;VBA是一种基于微软的Visual Basic语言的宏编程语言&#xff0c;专为在Office应用程序中执行自动化任务而设计。 VBA适用于Excel、Word、PowerPoint等Office套件中的宏编程&#xff0c;可直接操作和控制Office应用程序的对象模型。 我们…

Golang Gorm 高级查询之where查询

插入测试数据 package mainimport ("fmt""gorm.io/driver/mysql""gorm.io/gorm" )type Student struct {ID int64Name string gorm:"size:6"Age intEmail *string }func (*Student) TableName() string {return "student&q…

名片扫描仪有何优缺点?要不要买?

名片扫描仪是一种专用设备&#xff0c;用于将纸质名片上的信息转换为数字格式。它可以通过光学字符识别&#xff08;OCR&#xff09;技术将名片上的文本、图像和其他数据提取出来&#xff0c;并将其保存为电子文件或导入到相关应用程序中。 名片扫描仪是一种年代比较久的产品了…

申请甲骨文免费vps的流程

前提&#xff1a;拥有一张VISA信用卡或者mastercard信用卡 背景&#xff1a;甲骨文的免费VPS&#xff0c;已经使用了一年了&#xff0c;不得不说还是很香的。当时申请的节点是日本的&#xff0c;这次想申请一个美国的&#xff0c;话不多说,开冲。 最初申请的时候也是失败了好多…

【Terraform学习】使用 Terraform 从 EC2 实例访问 S3 存储桶(Terraform-AWS最佳实战学习)

使用 Terraform 从 EC2 实例访问 S3 存储桶 实验步骤 前提条件 安装 Terraform&#xff1a; 地址 下载仓库代码模版 本实验代码位于 task_ec2_s3connet 文件夹中。 变量文件 variables.tf 在上面的代码中&#xff0c;您将声明&#xff0c;aws_access_key&#xff0c;aws_…

linux 同时kill杀死多进程实践

使用场景 当程序中有使用到多进程且进程数较多的情况&#xff0c;如下图&#xff0c;且需要通过控制台杀死所有的 GSM_run.py 的进程时&#xff0c;利用 kill 命令一个一个的去结束进程是及其耗时且繁琐的&#xff0c;这时就需要我们的kill多进程的命令工作了。 批量 Kill 进程…

分享好用的翻译软件

网易有道翻译→网易有道翻译

软件产品为什么需要做测试报告?

在当今数字化的时代&#xff0c;软件产品的开发和使用已经成为各行各业的常态。随着软件市场的竞争越来越激烈&#xff0c;用户对于软件品质和功能的要求也越来越高。而为了确保软件产品质量和稳定性&#xff0c;软件测试报告变得至关重要。 一、软件产品为什么要做测试报告?…

学习ts(七)泛型

定义 泛型允许我们在强类型程序设计语言中编写代码时使用一些以后才指定的类型&#xff0c;在实例化时作为参数指明这些类型。在ts中&#xff0c;定义函数、接口或类的时候&#xff0c;不预先定义好具体的类型&#xff0c;而在使用的时候在指定类型的一种特性。 例子&#xff…