mac深度学习pytorch:ResNet50网络图像分类篇——花数据集图像分类(5类)保姆级详细过程及可视化

原代码及数据集下载:【度学习pytorch实战六:ResNet50网络图像分类篇自建花数据集图像分类(5类)超详细代码 -  CSDN App】/windows度学习pytorch实战六:ResNet50网络图像分类篇自建花数据集图像分类(5类)超详细代码_resnet50图像分类-CSDN博客

1.数据集

下载数据集至本地(点击原文链接进行下载)

2.代码

2.1数据预处理

**windows:**
import os
from shutil import copy
import random

def mkfile(file):
    if not os.path.exists(file):
        os.makedirs(file)

# 获取 photos 文件夹下除 .txt 文件以外所有文件夹名(即3种分类的类名)
file_path = 'yourdataroad/flower_photos'
flower_class = [cla for cla in os.listdir(file_path) if ".txt" not in cla]

# 创建 训练集train 文件夹,并由3种类名在其目录下创建3个子目录
mkfile('flower_data/train')
for cla in flower_class:
    mkfile('flower_data/train/' + cla)

# 创建 验证集val 文件夹,并由3种类名在其目录下创建3个子目录
mkfile('flower_data/val')
for cla in flower_class:
    mkfile('flower_data/val/' + cla)

# 划分比例,训练集 : 验证集 = 9 : 1
split_rate = 0.1

# 遍历3种花的全部图像并按比例分成训练集和验证集
for cla in flower_class:
    cla_path = file_path + '/' + cla + '/'  # 某一类别动作的子目录
    images = os.listdir(cla_path)  # iamges 列表存储了该目录下所有图像的名称
    num = len(images)
    eval_index = random.sample(images, k=int(num * split_rate))  # 从images列表中随机抽取 k 个图像名称
    for index, image in enumerate(images):
        # eval_index 中保存验证集val的图像名称
        if image in eval_index:
            image_path = cla_path + image
            new_path = 'flower_data/val/' + cla
            copy(image_path, new_path)  # 将选中的图像复制到新路径

        # 其余的图像保存在训练集train中
        else:
            image_path = cla_path + image
            new_path = 'flower_data/train/' + cla
            copy(image_path, new_path)
        print("\\r[{}] processing [{}/{}]".format(cla, index + 1, num), end="")  # processing bar
    print()

print("processing done!")

mac设备报错:

 File "/*/pytorch/resnet/data预处理.py", line 32, in <module>
    images = os.listdir(cla_path)  # iamges 列表存储了该目录下所有图像的名称
NotADirectoryError: [Errno 20] Not a directory: '/yourdataroad/flower_data/.DS_Store/'

错误信息表明在尝试列出目录内容时,cla_path 指向了一个不是目录的文件,具体来说是 /yourdataroad/flower_data/.DS_Store/.DS_Store 文件是 macOS 系统用来存储文件夹的自定义属性的隐藏文件,例如文件的图标位置和背景色等,它不是一个目录。

要修正这个错误,你需要在获取目录列表时排除 .DS_Store 文件

**macos**
import os
from shutil import copy
import random

def mkfile(file):
    if not os.path.exists(file):
        os.makedirs(file)

# 获取 photos 文件夹下除 .txt 文件以外所有文件夹名(即3种分类的类名)
file_path = '/yourdataroad/flower_data'
flower_class = [cla for cla in os.listdir(file_path) if os.path.isdir(os.path.join(file_path, cla)) and ".txt" not in cla]

# 创建 训练集train 文件夹,并由3种类名在其目录下创建3个子目录
mkfile('flower_data/train')
for cla in flower_class:
    mkfile('flower_data/train/' + cla)

# 创建 验证集val 文件夹,并由3种类名在其目录下创建3个子目录
mkfile('flower_data/val')
for cla in flower_class:
    mkfile('flower_data/val/' + cla)

# 划分比例,训练集 : 验证集 = 9 : 1
split_rate = 0.1

# 遍历3种花的全部图像并按比例分成训练集和验证集
for cla in flower_class:
    cla_path = os.path.join(file_path, cla)  # 某一类别动作的子目录
    images = [img for img in os.listdir(cla_path) if os.path.isfile(os.path.join(cla_path, img))]  # 确保是文件
    num = len(images)
    eval_index = random.sample(images, k=int(num * split_rate))  # 从images列表中随机抽取 k 个图像名称
    for index, image in enumerate(images):
        # eval_index 中保存验证集val的图像名称
        if image in eval_index:
            image_path = os.path.join(cla_path, image)
            new_path = os.path.join('flower_data/val', cla)
            copy(image_path, new_path)  # 将选中的图像复制到新路径

        # 其余的图像保存在训练集train中
        else:
            image_path = os.path.join(cla_path, image)
            new_path = os.path.join('flower_data/train', cla)
            copy(image_path, new_path)
        print("\\r[{}] processing [{}/{}]".format(cla, index + 1, num), end="")  # processing bar
    print()

print("processing done!")

代码运行结果:

2.2训练模型

假设你已知restnet网络原理,不知道也没关系。以下是在macos上运行的完整代码,windows或其他版本可以去看本文开头链接。

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms, models
import numpy as np
import matplotlib.pyplot as plt
import os

# 定义数据转换
data_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}

# 加载数据集
data_dir = '/Users/xiaqizai/Downloads/flower_data'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),
                                          data_transforms[x])
                  for x in ['train', 'val']}
dataloaders = {x: DataLoader(image_datasets[x], batch_size=4,
                             shuffle=True, num_workers=4)
               for x in ['train', 'val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
class_names = image_datasets['train'].classes

# 加载预训练的ResNet-50模型
model = models.resnet50(weights=models.ResNe
<think>嗯,用户想让我写一份在Windows系统下使用PyTorch框架,配合数据增强来训练ResNet50模型在MNIST数据集上的代码。首先,我需要理清楚整个流程,确保每个步骤都正确无误。 首先,ResNet50原本是为ImageNet设计的,输入是3通道的224x224图像,而MNIST是单通道的28x28的灰度图。所以必须调整ResNet50的输入层,将第一层卷积的输入通道改为1,同时可能需要调整后续的全连接层输出为10。另外,图像尺寸的问题,是否需要将28x28上采样到224x224?或者修改ResNet的结构,比如减少层数或调整卷积参数?不过ResNet50本身比较深,可能对于MNIST来说有点过大,容易过拟合,但用户明确要求ResNet50,所以得按照要求来。 接下来是数据增强的部分。PyTorch的transforms提供了很多方法,比如随机旋转、缩放、裁剪、调整亮度对比度等。但MNIST是手写数字,一些增强可能不太适用,比如颜色抖动,因为是灰度图。不过可以加上旋转、轻微平移、缩放等。需要注意,数据增强需要在训练集上应用,而测试集则只需要基础的处理,比如转为Tensor和归一化。 然后是数据加载部分。使用torchvision.datasets.MNIST下载数据集,设置好数据增强的transform。数据加载器要分训练和测试,batch_size一般设为64或128,视显存情况而定。 模型构建方面,修改ResNet50的输入通道,并且输出层改为10个节点。PyTorch中的ResNet50第一层是conv1,即7x7的卷积,输入通道3,改为1。同时,全连接层的输入特征数是2048,输出改为10。另外,因为输入图像尺寸可能不够,如果保持原来的ResNet50结构,可能需要调整前面的层,或者将MNIST图像上采样到更大的尺寸。例如,将28x28的图像通过插值扩大到224x224,这样ResNet50的结构就不用改太多。或者,修改ResNet的第一层卷积参数,比如kernel_size和stride,使得网络能够处理较小的输入。但这样可能会影响后续层的结构,导致尺寸计算错误。稳妥的做法可能是将图像resize到224x224,这样ResNet50的结构不需要修改,除了输入通道和输出层。 归一化的参数可能需要调整。通常ImageNet用的是mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225],但MNIST是单通道,所以可能需要计算MNIST的均值和标准差。MNIST的像素值在0-1之间,归一化可以设为mean=(0.1307,), std=(0.3081,),这些是常用的参数。 训练循环部分,需要定义损失函数(交叉熵),优化器(如Adam或SGD),学习率调整等。训练过程中要记录损失和准确率,可能还需要在测试集上验证模型性能,防止过拟合。 代码的结构大概分为几个部分:导入库、设置设备(CUDA)、定义数据增强、加载数据集、定义模型、训练和测试函数、主循环。 可能遇到的问题包括:输入通道的问题,如果ResNet50的输入层没有正确修改会导致运行时错误;图像尺寸的问题,如果输入尺寸不符合ResNet的要求,会在前向传播时出现尺寸不匹配;数据增强是否合理,比如过多的增强可能影响MNIST的可识别性;过拟合问题,因为ResNet50参数量大,而MNIST样本量相对较小,可能需要加入dropout或者更强的正则化,或者减少训练epoch。 现在具体步骤: 1. 导入必要的库:torch, torchvision, transforms, datasets, models, nn, optim等。 2. 定义数据增强的transforms:训练集使用RandomRotation、RandomAffine、ColorJitter(虽然单通道,可能用不上),RandomResizedCrop(如果调整尺寸的话),然后转为Tensor,归一化。测试集只需转为Tensor和归一化。 3. 加载MNIST数据集,应用transforms。可能需要使用ImageFolder或者其他方式,但MNIST是内置数据集,直接使用datasets.MNIST,设置download=True。 4. 修改ResNet50模型:调整conv1的输入通道为1,修改全连接层输出为10。注意,如果使用预训练的ResNet50,则无法直接使用,因为输入通道不同,且任务不同。所以这里应该不使用预训练,随机初始化。 5. 定义损失函数和优化器,如CrossEntropyLoss和Adam。 6. 训练循环:迭代数据,前向传播,计算损失,反向传播,优化。每个epoch后在测试集上验证准确率。 可能的代码结构: - 设置设备:device = 'cuda' if torch.cuda.is_available() else 'cpu' - 数据增强部分: train_transform = transforms.Compose([ transforms.RandomRotation(10), transforms.RandomAffine(degrees=0, translate=(0.1,0.1)), transforms.Resize(224), # 调整尺寸到224x224 transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) test_transform = transforms.Compose([ transforms.Resize(224), transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) 但MNIST原始是28x28,直接resize到224会引入插值,可能影响性能。或者考虑修改ResNet的结构,使其接受较小的输入,但ResNet50的设计可能需要较大的输入尺寸。所以resize到224可能更简单。 然后加载数据集: trainset = datasets.MNIST(root='./data', train=True, download=True, transform=train_transform) testset = datasets.MNIST(root='./data', train=False, download=True, transform=test_transform) 创建DataLoader,batch_size设为合适的值,比如128。 定义模型: model = models.resnet50(pretrained=False) model.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False) model.fc = nn.Linear(2048, 10) # 原ResNet50的fc层输入是2048 model.to(device) 定义优化器和损失函数: criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) 训练循环: for epoch in range(num_epochs): model.train() for images, labels in train_loader: images, labels = images.to(device), labels.to(device) optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() # 测试部分 model.eval() correct = 0 total = 0 with torch.no_grad(): for images, labels in test_loader: images, labels = images.to(device), labels.to(device) outputs = model(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() accuracy = 100 * correct / total print(f'Epoch {epoch+1}, Test Accuracy: {accuracy}%') 此外,可能需要调整学习率,或者添加学习率调度器。另外,训练时可能因为ResNet50较深而需要较多epoch,但MNIST可能在较少的epoch就收敛。 验证数据增强是否正确应用,比如查看是否在训练时进行了旋转、平移等操作。 另外,注意ResNet的Batch Normalization层在训练和评估模式下的不同行为,所以在测试时需要调用model.eval()。 最后,确保代码在Windows下能运行,特别是路径方面没有问题,比如数据集下载路径是否正确,是否有写入权限等。</think>以下是一份在Windows系统下使用PyTorch框架训练ResNet50模型,并包含数据增强的MNIST训练代码代码分为数据准备、模型定义、训练流程三部分: --- ### 一、环境准备 ```python import torch import torch.nn as nn import torch.optim as optim import torchvision from torchvision import transforms, datasets from torch.utils.data import DataLoader # 检查GPU可用性 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(f"当前使用设备: {device}") ``` --- ### 二、数据增强与加载 ```python # 定义数据增强组合 train_transform = transforms.Compose([ transforms.RandomRotation(10), # 随机旋转±10度 transforms.RandomAffine(0, translate=(0.1, 0.1)), # 随机平移10% transforms.Resize(224), # 调整尺寸适配ResNet输入 transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) # MNIST标准归一化参数 ]) test_transform = transforms.Compose([ transforms.Resize(224), transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) # 加载MNIST数据集 train_set = datasets.MNIST( root='./data', train=True, download=True, transform=train_transform ) test_set = datasets.MNIST( root='./data', train=False, download=True, transform=test_transform ) # 创建数据加载器 batch_size = 64 train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True) test_loader = DataLoader(test_set, batch_size=batch_size, shuffle=False) ``` --- ### 三、模型定义与修改 ```python # 修改ResNet50适配MNIST model = torchvision.models.resnet50(pretrained=False) # 修改首层卷积(原始输入通道3改为1) model.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False) # 修改最后一层全连接(输出别改为10) model.fc = nn.Linear(model.fc.in_features, 10) model = model.to(device) ``` --- ### 四、训练配置 ```python criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) num_epochs = 10 ``` --- ### 五、训练与验证循环 ```python for epoch in range(num_epochs): # 训练模式 model.train() running_loss = 0.0 for images, labels in train_loader: images = images.to(device) labels = labels.to(device) optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() # 验证模式 model.eval() correct = 0 total = 0 with torch.no_grad(): for images, labels in test_loader: images = images.to(device) labels = labels.to(device) outputs = model(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() # 输出统计信息 train_loss = running_loss / len(train_loader) test_acc = 100 * correct / total print(f"Epoch [{epoch+1}/{num_epochs}] | " f"训练损失: {train_loss:.4f} | " f"测试准确率: {test_acc:.2f}%") ``` --- ### 六、关键说明 1. **输入适配**:通过修改首层卷积通道数(3→1)和调整输入尺寸(28→224)适配MNIST 2. **数据增强**:包含旋转、平移等增强策略,提升模型泛化能力 3. **性能优化**:使用Adam优化器加速收敛,可根据显存调整batch_size 4. **注意事项**: - 建议在GPU环境下运行(需安装CUDA版PyTorch) - 可添加学习率调度器(如`lr_scheduler.StepLR`)进一步优化 - 可通过`torchsummary`库可视化网络结构 完整代码需配合Python 3.8+、PyTorch 1.12+环境运行。首次运行会自动下载MNIST数据集至`./data`目录。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值