第P4周:猴痘病识别

一、前期准备

1.设置GPU

python 复制代码
''' 设置GPU '''
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("Using {} device".format(device))

没有GPU则使用CPU

2.导入数据、数据预处理

python 复制代码
import os,PIL,random,pathlib
data_dir = r'D:\P4'
data_dir = pathlib.Path(data_dir)

data_paths = list(data_dir.glob('*'))
class_names = [path.name for path in data_paths]
print(class_names)
python 复制代码
import pathlib
import torchvision.transforms as transforms
from torchvision import datasets
total_datadir = r'D:\P4'

train_transforms = transforms.Compose([
    transforms.Resize([224, 224]),
    transforms.ToTensor(),
    transforms.Normalize(
        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)

定义数据预处理操作 train_transforms

  • transforms.Resize([224, 224]):将输入图像的尺寸调整为 224x224 像素,这通常是训练深度学习模型所使用的常见图像尺寸。
  • transforms.ToTensor():将图像数据转换为PyTorch张量,并将像素值归一化到范围 [0, 1]。
  • transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]):对图像进行标准化处理,将像素值标准化为标准正态分布(高斯分布),这有助于模型更快地收敛。

使用 datasets.ImageFolder 加载图像数据集:

  • total_datadir 是包含图像数据集的目录路径。
  • transform=train_transforms 指定了要应用的数据预处理操作。

3.标签映射

在DatasetFolder中,class_to_idx是一个字典,将类别名映射到类别标签(从0开始),其中类别名是文件夹的名称,类别标签是与之相关联的数字。

为什么要做标签映射呢?

  • 将类别名映射到类别标签是因为在训练深度学习模型时,通常使用类别标签来表示每个样本的类别。
  • 在训练模型时,输入数据被转换为张量,并且每个张量的标签是一个数字,表示与之相关联的类别。
  • 类别标签使得模型可以根据真实标签和预测标签之间的误差来更新模型权重,从而使模型学习到如何将输入数据映射到正确的输出标签。
python 复制代码
print(total_data.class_to_idx)

二、划分数据集

python 复制代码
import torch
from torch.utils.data import DataLoader

# total_data 包含了数据集,我们可以从 total_data 中划分出训练集和测试集
# 例如,可以按照一定的比例划分数据集,或者根据需要自定义训练集和测试集

# 划分数据集示例:
# 假设数据集总共有100个样本,可以将前80个样本用于训练,后20个用于测试
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])

batch_size = 32

train_dl = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=1)
test_dl = DataLoader(test_dataset, batch_size=batch_size, shuffle=True, num_workers=1)

三、 构建 CNN 网络

python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F

class Network(nn.Module):
    def __init__(self):
        super(Network, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 53 * 53, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 2)
        self.dropout = nn.Dropout(0.5)  # Adding dropout with a probability of 0.5

    def forward(self, x):
        x = F.max_pool2d(F.relu(self.conv1(x)), 2)
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        x = x.view(-1, 16 * 53 * 53)
        x = F.relu(self.fc1(x))
        x = self.dropout(x)  # Applying dropout after the first fully connected layer
        x = F.relu(self.fc2(x))
        x = self.dropout(x)  # Applying dropout after the second fully connected layer
        x = self.fc3(x)
        x = F.log_softmax(x, dim=1)
        return x

model = Network()
print(model)

四、训练模型

1. 设置超参数

python 复制代码
# 定义损失函数和优化器
loss_fn = nn.CrossEntropyLoss()
leaining_rate = 0.001
opt = torch.optim.Adam(model.parameters(),lr=leaining_rate)

2.编写训练函数

python 复制代码
# 训练函数
def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)

    train_loss, train_acc = 0, 0
    for x, y in dataloader:
        x, y  = x.to(device), y.to(device)

        # Compute prediction error
        pred = model(x) # 网络输出
        loss = loss_fn(pred, y) # 计算损失

        optimizer.zero_grad() # 梯度清零
        loss.backward() # 反向传播
        optimizer.step() # 更新参数

        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

# 测试函数
def test(dataloader, model, loss_fn):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)

    test_loss, test_acc = 0, 0
    with torch.no_grad():
        for x, y in dataloader:
            x, y  = x.to(device), y.to(device)

            pred = model(x)
            loss = loss_fn(pred, y)

            test_loss += loss_fn(pred, y).item()
            test_acc += (pred.argmax(1) == y).type(torch.float).sum().item()

    test_acc /= size
    test_loss /= num_batches

    return test_acc, test_loss

3.正式训练

python 复制代码
epochs     = 20
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')

代码在运行时出现下列问题可能是以下原因导致:

Traceback (most recent call last):

File "<string>", line 1, in <module>

File "D:\Python\lib\multiprocessing\spawn.py", line 116, in spawn_main

exitcode = _main(fd, parent_sentinel)

File "D:\Python\lib\multiprocessing\spawn.py", line 125, in _main

prepare(preparation_data)

File "D:\Python\lib\multiprocessing\spawn.py", line 236, in prepare

_fixup_main_from_path(data['init_main_from_path'])

File "D:\Python\lib\multiprocessing\spawn.py", line 287, in _fixup_main_from_path

main_content = runpy.run_path(main_path,

File "D:\Python\lib\runpy.py", line 289, in run_path

return _run_module_code(code, init_globals, run_name,

File "D:\Python\lib\runpy.py", line 96, in _run_module_code

_run_code(code, mod_globals, init_globals,

File "D:\Python\lib\runpy.py", line 86, in _run_code

exec(code, run_globals)

File "c:\Users\刘鸿逸\Desktop\python\01.py", line 156, in <module>

epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt)

File "c:\Users\刘鸿逸\Desktop\python\01.py", line 105, in train

for X, y in dataloader: # 获取图片及其标签

File "D:\Python\lib\site-packages\torch\utils\data\dataloader.py", line 441, in iter

return self._get_iterator()

File "D:\Python\lib\site-packages\torch\utils\data\dataloader.py", line 388, in _get_iterator

return _MultiProcessingDataLoaderIter(self)

File "D:\Python\lib\site-packages\torch\utils\data\dataloader.py", line 1042, in init

w.start()

File "D:\Python\lib\multiprocessing\process.py", line 121, in start

self._popen = self._Popen(self)

File "D:\Python\lib\multiprocessing\context.py", line 224, in _Popen

return _default_context.get_context().Process._Popen(process_obj)

File "D:\Python\lib\multiprocessing\context.py", line 336, in _Popen

return Popen(process_obj)

File "D:\Python\lib\multiprocessing\popen_spawn_win32.py", line 45, in init

prep_data = spawn.get_preparation_data(process_obj._name)

File "D:\Python\lib\multiprocessing\spawn.py", line 154, in get_preparation_data

_check_not_importing_main()

File "D:\Python\lib\multiprocessing\spawn.py", line 134, in _check_not_importing_main

raise RuntimeError('''

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.

这个错误是由于在Windows操作系统上使用多进程时,未按照正确的方式设置了启动子进程的方法引起的。它提示需要在主模块中添加适当的if __name__ == '__main__':块以正确启动子进程。下面解释一下报错的含义以及如何解决它:

  • 为了解决这个问题,应该确保在主模块中使用if __name__ == '__main__':块来包装主要的执行代码,这是一种在使用多进程时常见的做法。
  • 在主模块中包装代码后,子进程将只在主进程中执行,而不会在导入模块时执行。这可以防止上述报错。

修改后完整代码:

python 复制代码
import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torchvision
from torchvision import transforms, datasets
import os
import PIL
import pathlib

# Your code for data loading, model definition, training, and testing should go here

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

    print(device)

    import os,PIL,random,pathlib
    data_dir = r'D:\P4'
    data_dir = pathlib.Path(data_dir)

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

    total_datadir = r'D:\P4'
    # 关于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)

    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)

    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)

    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

    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

    epochs     = 17
    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')

验证集正确率达到88%以上。

相关推荐
封步宇AIGC15 分钟前
量化交易系统开发-实时行情自动化交易-Okex K线数据
人工智能·python·机器学习·数据挖掘
封步宇AIGC18 分钟前
量化交易系统开发-实时行情自动化交易-Okex交易数据
人工智能·python·机器学习·数据挖掘
z千鑫20 分钟前
【人工智能】利用大语言模型(LLM)实现机器学习模型选择与实验的自动化
人工智能·gpt·机器学习·语言模型·自然语言处理·自动化·codemoss
小爬虫程序猿20 分钟前
如何利用Python解析API返回的数据结构?
数据结构·数据库·python
shelly聊AI21 分钟前
AI赋能财务管理,AI技术助力企业自动化处理财务数据
人工智能·财务管理
波点兔22 分钟前
【部署glm4】属性找不到、参数错误问题解决(思路:修改模型包版本)
人工智能·python·机器学习·本地部署大模型·chatglm4
佚明zj1 小时前
全卷积和全连接
人工智能·深度学习
一点媛艺3 小时前
Kotlin函数由易到难
开发语言·python·kotlin
qzhqbb4 小时前
基于统计方法的语言模型
人工智能·语言模型·easyui
冷眼看人间恩怨4 小时前
【话题讨论】AI大模型重塑软件开发:定义、应用、优势与挑战
人工智能·ai编程·软件开发