P4周:猴痘病识别

环境配置:
Python 3.11.4

Pytorch 2.0.1

torchvision 0.15.2+cpu

本次图像数据集为K同学提供,若需获取,请联系K同学。

一、前期准备

1.​​设置GPU

import torch
import torch.nn as nn
from matplotlib import pyplot as plt
from torchvision import transforms, datasets

if __name__ == '__main__':
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    print(device)

结果显示

cuda

这里没有使用原先的代码

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device

因为如果按照K同学构建模型时会提示错误

RuntimeError:
        An attempt has been made to start a new process before the
        current process has finished its bootstrapping phase.

        This probably means that you are not using fork to start your
        child processes and you have forgotten to use the proper idiom
        in the main module:

            if __name__ == '__main__':
                freeze_support()
                ...

        The "freeze_support()" line can be omitted if the program
        is not going to be frozen to produce an executable.

而这个错误是由于未按照正确的方式设置启动子进程的方法导致的。它提示需要在主模块中添加适当的if name == ‘main’:块以正确启动子进程。于是就在主模块中添加if name == ‘main’:以包装代码。

2.导入所需数据并进行预处理

将K同学提供的图片进行下载,并将路径设置好方便引用。
● 第一步:使用pathlib.Path()函数将字符串类型的文件夹路径转换为pathlib.Path对象。
● 第二步:使用glob()方法获取data_dir路径下的所有文件路径,并以列表形式存储在data_paths中。
● 第三步:通过split()函数对data_paths中的每个文件路径执行分割操作,获得各个文件所属的类别名称,并存储在classeNames中
● 第四步:打印classeNames列表,显示每个文件所属的类别名称。

 import pathlib

    data_dir = './data-4/'
    data_dir = pathlib.Path(data_dir)

    data_paths = list(data_dir.glob('*'))
    class_names = [path.name for path in data_paths]
    print(class_names)

打印出class_names

['Monkeypox', 'Others']

进行数据预处理:将图片裁剪为统一尺寸并转化为张量,并将张量进行归一化,然后进行标准化处理,最后使用datasets.ImageFolder 加载图像数据集。

total_datadir = './data-4/'
    # 关于transforms.Compose的更多介绍可以参考:https://blog.csdn.net/qq_38251616/article/details/124878863
    train_transforms = transforms.Compose([
        transforms.Resize([224, 224]),  # 将输入图片resize成统一尺寸
        transforms.ToTensor(),  # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间
        transforms.Normalize(  # 标准化处理-->转换为标准正太分布(高斯分布),使模型更容易收敛
            mean=[0.485, 0.456, 0.406],
            std=[0.229, 0.224, 0.225])  # 其中 mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。
    ])

    total_data = datasets.ImageFolder(total_datadir, transform=train_transforms)
    print(total_data)

打印如下

Dataset ImageFolder
    Number of datapoints: 2142
    Root location: ./data-4/
    StandardTransform
Transform: Compose(
               Resize(size=[224, 224], interpolation=bilinear, max_size=None, antialias=warn)
               ToTensor()
               Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
           )

3.划分数据集

将训练集与测试集比例设置为0.8:0.2,并将batch_size设置为32,进行划分。

    train_size = int(0.8 * len(total_data))
    test_size = len(total_data) - train_size
    train_dataset, test_dataset = torch.utils.data.random_split(total_data, [train_size, test_size])
    print(train_dataset, test_dataset)

    batch_size = 32

    train_dl = torch.utils.data.DataLoader(train_dataset,
                                           batch_size=batch_size,
                                           shuffle=True,
                                           num_workers=1)
    test_dl = torch.utils.data.DataLoader(test_dataset,
                                          batch_size=batch_size,
                                          shuffle=True,
                                          num_workers=1)

打印如下

<torch.utils.data.dataset.Subset object at 0x000002A9DF21F2E0> 
<torch.utils.data.dataset.Subset object at 0x000002A9DF21F340>

二、构建网络模型

1.搭建CNN网络

在这里插入图片描述

    import torch.nn.functional as F


    class Network_bn(nn.Module):
        def __init__(self):
            super(Network_bn, self).__init__()
            """
            nn.Conv2d()函数:
            第一个参数(in_channels)是输入的channel数量
            第二个参数(out_channels)是输出的channel数量
            第三个参数(kernel_size)是卷积核大小
            第四个参数(stride)是步长,默认为1
            第五个参数(padding)是填充大小,默认为0
            """
            self.conv1 = nn.Conv2d(in_channels=3, out_channels=12, kernel_size=5, stride=1, padding=0)
            self.bn1 = nn.BatchNorm2d(12)
            self.conv2 = nn.Conv2d(in_channels=12, out_channels=12, kernel_size=5, stride=1, padding=0)
            self.bn2 = nn.BatchNorm2d(12)
            self.pool = nn.MaxPool2d(2, 2)
            self.conv4 = nn.Conv2d(in_channels=12, out_channels=24, kernel_size=5, stride=1, padding=0)
            self.bn4 = nn.BatchNorm2d(24)
            self.conv5 = nn.Conv2d(in_channels=24, out_channels=24, kernel_size=5, stride=1, padding=0)
            self.bn5 = nn.BatchNorm2d(24)
            self.fc1 = nn.Linear(24 * 50 * 50, len(class_names))

        def forward(self, x):
            x = F.relu(self.bn1(self.conv1(x)))
            x = F.relu(self.bn2(self.conv2(x)))
            x = self.pool(x)
            x = F.relu(self.bn4(self.conv4(x)))
            x = F.relu(self.bn5(self.conv5(x)))
            x = self.pool(x)
            x = x.view(-1, 24 * 50 * 50)
            x = self.fc1(x)

            return x


    device = "cuda" if torch.cuda.is_available() else "cpu"
    print("Using {} device".format(device))

    model = Network_bn().to(device)
    print(model)

打印结果如下

Using cuda device
Network_bn(
  (conv1): Conv2d(3, 12, kernel_size=(5, 5), stride=(1, 1))
  (bn1): BatchNorm2d(12, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (conv2): Conv2d(12, 12, kernel_size=(5, 5), stride=(1, 1))
  (bn2): BatchNorm2d(12, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (conv4): Conv2d(12, 24, kernel_size=(5, 5), stride=(1, 1))
  (bn4): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (conv5): Conv2d(24, 24, kernel_size=(5, 5), stride=(1, 1))
  (bn5): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (fc1): Linear(in_features=60000, out_features=2, bias=True)
)

2.训练

使用交叉熵损失函数,设置学习率,优化函数

    loss_fn = nn.CrossEntropyLoss()  # 创建损失函数
    learn_rate = 1e-4  # 学习率
    opt = torch.optim.SGD(model.parameters(), lr=learn_rate)

编写训练函数

    def train(dataloader, model, loss_fn, optimizer):
        size = len(dataloader.dataset)  # 训练集的大小,一共60000张图片
        num_batches = len(dataloader)  # 批次数目,1875(60000/32)

        train_loss, train_acc = 0, 0  # 初始化训练损失和正确率

        for X, y in dataloader:  # 获取图片及其标签
            X, y = X.to(device), y.to(device)

            # 计算预测误差
            pred = model(X)  # 网络输出
            loss = loss_fn(pred, y)  # 计算网络输出和真实值之间的差距,targets为真实值,计算二者差值即为损失

            # 反向传播
            optimizer.zero_grad()  # grad属性归零
            loss.backward()  # 反向传播
            optimizer.step()  # 每一步自动更新

            # 记录acc与loss
            train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()
            train_loss += loss.item()

        train_acc /= size
        train_loss /= num_batches

        return train_acc, train_loss

3.测试

    def test(dataloader, model, loss_fn):
        size = len(dataloader.dataset)  # 测试集的大小,一共10000张图片
        num_batches = len(dataloader)  # 批次数目,313(10000/32=312.5,向上取整)
        test_loss, test_acc = 0, 0

        # 当不进行训练时,停止梯度更新,节省计算内存消耗
        with torch.no_grad():
            for imgs, target in dataloader:
                imgs, target = imgs.to(device), target.to(device)

                # 计算loss
                target_pred = model(imgs)
                loss = loss_fn(target_pred, target)

                test_loss += loss.item()
                test_acc += (target_pred.argmax(1) == target).type(torch.float).sum().item()

        test_acc /= size
        test_loss /= num_batches

        return test_acc, test_loss

三、正式训练

1.进行训练

    epochs = 50
    train_loss, train_acc, test_loss, test_acc = [], [], [], []
    for epoch in range(epochs):
        model.train()
        epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt)
        model.eval()
        epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)
        train_acc.append(epoch_train_acc)
        train_loss.append(epoch_train_loss)
        test_acc.append(epoch_test_acc)
        test_loss.append(epoch_test_loss)
        template = ('Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}%, Test_acc:{:.1f}%, Test_loss:{:.3f}%,')
        print(
            template.format(epoch + 1, epoch_train_acc * 100, epoch_train_loss, epoch_test_acc * 100, epoch_test_loss))
    print('Done')

训练50epochs并打印出结果

Epoch: 1, Train_acc:59.1%, Train_loss:0.699%, Test_acc:66.7%, Test_loss:0.626%,
Epoch: 2, Train_acc:68.2%, Train_loss:0.586%, Test_acc:66.0%, Test_loss:0.650%,
Epoch: 3, Train_acc:74.2%, Train_loss:0.531%, Test_acc:69.7%, Test_loss:0.600%,
Epoch: 4, Train_acc:77.6%, Train_loss:0.490%, Test_acc:75.1%, Test_loss:0.524%,
Epoch: 5, Train_acc:81.2%, Train_loss:0.447%, Test_acc:75.1%, Test_loss:0.494%,
Epoch: 6, Train_acc:82.4%, Train_loss:0.428%, Test_acc:74.6%, Test_loss:0.482%,
Epoch: 7, Train_acc:83.5%, Train_loss:0.406%, Test_acc:76.7%, Test_loss:0.481%,
Epoch: 8, Train_acc:86.9%, Train_loss:0.371%, Test_acc:81.6%, Test_loss:0.433%,
Epoch: 9, Train_acc:87.3%, Train_loss:0.360%, Test_acc:81.4%, Test_loss:0.422%,
Epoch:10, Train_acc:88.1%, Train_loss:0.339%, Test_acc:83.0%, Test_loss:0.410%,
Epoch:11, Train_acc:89.1%, Train_loss:0.323%, Test_acc:81.8%, Test_loss:0.421%,
Epoch:12, Train_acc:90.2%, Train_loss:0.312%, Test_acc:83.0%, Test_loss:0.396%,
Epoch:13, Train_acc:90.5%, Train_loss:0.298%, Test_acc:84.8%, Test_loss:0.396%,
Epoch:14, Train_acc:91.2%, Train_loss:0.287%, Test_acc:85.5%, Test_loss:0.384%,
Epoch:15, Train_acc:91.0%, Train_loss:0.286%, Test_acc:81.8%, Test_loss:0.432%,
Epoch:16, Train_acc:91.5%, Train_loss:0.274%, Test_acc:84.6%, Test_loss:0.378%,
Epoch:17, Train_acc:91.7%, Train_loss:0.267%, Test_acc:83.7%, Test_loss:0.387%,
Epoch:18, Train_acc:93.1%, Train_loss:0.247%, Test_acc:85.1%, Test_loss:0.362%,
Epoch:19, Train_acc:93.1%, Train_loss:0.246%, Test_acc:84.8%, Test_loss:0.368%,
Epoch:20, Train_acc:93.2%, Train_loss:0.240%, Test_acc:86.0%, Test_loss:0.355%,
Epoch:21, Train_acc:94.3%, Train_loss:0.231%, Test_acc:86.0%, Test_loss:0.352%,
Epoch:22, Train_acc:94.9%, Train_loss:0.223%, Test_acc:86.2%, Test_loss:0.346%,
Epoch:23, Train_acc:94.3%, Train_loss:0.219%, Test_acc:86.7%, Test_loss:0.344%,
Epoch:24, Train_acc:94.7%, Train_loss:0.205%, Test_acc:85.5%, Test_loss:0.349%,
Epoch:25, Train_acc:94.9%, Train_loss:0.207%, Test_acc:84.8%, Test_loss:0.344%,
Epoch:26, Train_acc:95.0%, Train_loss:0.203%, Test_acc:85.5%, Test_loss:0.347%,
Epoch:27, Train_acc:95.3%, Train_loss:0.197%, Test_acc:86.0%, Test_loss:0.345%,
Epoch:28, Train_acc:95.3%, Train_loss:0.189%, Test_acc:86.5%, Test_loss:0.332%,
Epoch:29, Train_acc:95.3%, Train_loss:0.190%, Test_acc:86.0%, Test_loss:0.345%,
Epoch:30, Train_acc:95.8%, Train_loss:0.183%, Test_acc:84.8%, Test_loss:0.332%,
Epoch:31, Train_acc:96.4%, Train_loss:0.177%, Test_acc:85.5%, Test_loss:0.346%,
Epoch:32, Train_acc:96.3%, Train_loss:0.173%, Test_acc:87.2%, Test_loss:0.332%,
Epoch:33, Train_acc:95.9%, Train_loss:0.175%, Test_acc:86.9%, Test_loss:0.331%,
Epoch:34, Train_acc:96.2%, Train_loss:0.170%, Test_acc:85.1%, Test_loss:0.353%,
Epoch:35, Train_acc:96.4%, Train_loss:0.163%, Test_acc:87.2%, Test_loss:0.323%,
Epoch:36, Train_acc:96.4%, Train_loss:0.158%, Test_acc:87.2%, Test_loss:0.312%,
Epoch:37, Train_acc:97.1%, Train_loss:0.153%, Test_acc:87.2%, Test_loss:0.323%,
Epoch:38, Train_acc:97.1%, Train_loss:0.154%, Test_acc:87.2%, Test_loss:0.317%,
Epoch:39, Train_acc:97.5%, Train_loss:0.143%, Test_acc:86.9%, Test_loss:0.316%,
Epoch:40, Train_acc:97.3%, Train_loss:0.144%, Test_acc:87.2%, Test_loss:0.314%,
Epoch:41, Train_acc:97.0%, Train_loss:0.148%, Test_acc:86.0%, Test_loss:0.329%,
Epoch:42, Train_acc:97.5%, Train_loss:0.138%, Test_acc:86.9%, Test_loss:0.309%,
Epoch:43, Train_acc:96.9%, Train_loss:0.144%, Test_acc:86.9%, Test_loss:0.319%,
Epoch:44, Train_acc:97.7%, Train_loss:0.134%, Test_acc:87.4%, Test_loss:0.310%,
Epoch:45, Train_acc:97.4%, Train_loss:0.133%, Test_acc:85.3%, Test_loss:0.329%,
Epoch:46, Train_acc:98.2%, Train_loss:0.130%, Test_acc:87.6%, Test_loss:0.310%,
Epoch:47, Train_acc:97.6%, Train_loss:0.128%, Test_acc:87.4%, Test_loss:0.304%,
Epoch:48, Train_acc:97.8%, Train_loss:0.125%, Test_acc:87.6%, Test_loss:0.306%,
Epoch:49, Train_acc:98.1%, Train_loss:0.121%, Test_acc:87.6%, Test_loss:0.316%,
Epoch:50, Train_acc:97.9%, Train_loss:0.123%, Test_acc:87.2%, Test_loss:0.316%,
Done

2.可视化

    import warnings

    warnings.filterwarnings("ignore")  # 忽略警告信息
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    plt.rcParams['figure.dpi'] = 100  # 分辨率

    epochs_range = range(epochs)

    plt.figure(figsize=(12, 3))
    plt.subplot(1, 2, 1)

    plt.plot(epochs_range, train_acc, label='Training Accuracy')
    plt.plot(epochs_range, test_acc, label='Test Accuracy')
    plt.legend(loc='lower right')
    plt.title('Training and Validation Accuracy')

    plt.subplot(1, 2, 2)
    plt.plot(epochs_range, train_loss, label='Training Loss')
    plt.plot(epochs_range, test_loss, label='Test Loss')
    plt.legend(loc='upper right')
    plt.title('Training and Validation Loss')
    plt.show()

将结果可视化
在这里插入图片描述

3.单张图片预测

classes = list(total_data.class_to_idx)
def predict_img(img_path, model, transform, classes):
    test_img = Image.open(img_path).convert('RGB')
    test_img = transform(test_img)
    img = test_img.to(device).unsqueeze(0)
    model.eval()
    output = model(img)
    _, pred = torch.max(output, 1)
    pred_class = classes[pred]
    print(f'预测结果是:{pred_class}')

进行预测

predict_img(img_path='./data-4/Monkeypox/M01_01_00.jpg', 
                  model=model, 
                  transform=train_transforms, 
                  classes=classes)

预测结果显示为Monkeypox

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值