花卉识别数据集-102种 使用 PyTorch 框架,并结合 torchvisionscipy 等工具训练并建立深度学习花卉图像分类系统
示例代码仅供参考。

数据集描述:
花卉识别数据集-102种
102 个种类的花卉图像,其目录结构中,jpg 文件夹存放所有格式为.jpg 的花卉图像
imagelabels.mat 包含图像的标签信息以标记花卉种类
setid.mat 包含训练集、验证集和测试集的图像 ID 划分
train_extra_list.txt 列出训练的额外图像文件及其标签
train_list.txt 和 val_list.txt 分别列出训练集和验证集的图像文件及其标签。
图像文件在 jpg 文件夹中,标签文件有 imagelabels.mat 和 setid.mat
文本列表文件有 train_extra_list.txt、train_list.txt 和 val_list.txt
102 种花卉,图像数量依列表文件记录而定,每个图像有对应标签用于分类。使用时,可通过 train_list.txt 和 val_list.txt 加载训练集和验证集图像及其标签,利用 imagelabels.mat 获取图像标签信息,花卉分类任务,辅助训练和评估图像分类模型性能。

在这里插入图片描述

1
在这里插入图片描述
深度学习花卉图像分类系统(102种) 的训练流程,适用于你提到的 “花卉识别数据集-102种”。使用 PyTorch 框架,并结合 torchvisionscipy 等工具来加载和处理数据。


🌸 花卉识别数据集 - 102 类深度学习分类系统实现

✅ 数据结构说明

dataset/
├── jpg/                  # 所有 .jpg 图像文件
├── imagelabels.mat       # 图像标签 (1~102)
├── setid.mat             # 划分 ID(训练、验证、测试)
├── train_list.txt        # 训练集列表
├── val_list.txt          # 验证集列表
└── train_extra_list.txt  # 额外训练图像列表(可选)

🔧 第一步:安装依赖

pip install torch torchvision scipy matplotlib scikit-learn tqdm

📁 第二步:自定义 Dataset 加载器

根据 train_list.txtval_list.txt 文件读取图像路径和对应标签:

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

class Flowers102Dataset(Dataset):
    def __init__(self, root_dir, list_file, transform=None):
        self.root_dir = root_dir
        self.transform = transform
        self.image_paths, self.labels = self._load_list(os.path.join(root_dir, list_file))

    def _load_list(self, file_path):
        image_paths = []
        labels = []
        with open(file_path, 'r') as f:
            for line in f:
                img_name, label = line.strip().split()
                image_paths.append(os.path.join(self.root_dir, 'jpg', img_name))
                labels.append(int(label) - 1)  # 标签从0开始
        return image_paths, labels

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

    def __getitem__(self, idx):
        image_path = self.image_paths[idx]
        image = Image.open(image_path).convert('RGB')
        label = self.labels[idx]

        if self.transform:
            image = self.transform(image)

        return image, label

🎨 第三步:数据增强与预处理

from torchvision import transforms

transform_train = transforms.Compose([
    transforms.RandomResizedCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])

transform_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])
])

🏗️ 第四步:模型定义(推荐 ResNet50)

from torchvision import models
import torch.nn as nn

def get_model(num_classes=102, pretrained=True):
    model = models.resnet50(pretrained=pretrained)
    model.fc = nn.Linear(model.fc.in_features, num_classes)
    return model

🚀 第五步:训练与验证代码

import torch
from torch.utils.data import DataLoader
from torch import optim
from tqdm import tqdm

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

# 初始化数据集
root_dir = 'dataset'  # 替换为你的数据集路径
train_dataset = Flowers102Dataset(root_dir=root_dir, list_file='train_list.txt', transform=transform_train)
val_dataset = Flowers102Dataset(root_dir=root_dir, list_file='val_list.txt', transform=transform_val)

train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4)
val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, num_workers=4)

# 初始化模型
model = get_model()
model.to(device)

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)

# 训练循环
num_epochs = 30

for epoch in range(num_epochs):
    model.train()
    running_loss = 0.0
    progress_bar = tqdm(train_loader, desc=f"Epoch {epoch+1}/{num_epochs}")
    
    for images, labels in progress_bar:
        images, labels = images.to(device), labels.to(device)
        
        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        
        running_loss += loss.item() * images.size(0)
        progress_bar.set_postfix(loss=loss.item())
    
    scheduler.step()
    print(f"Epoch {epoch+1} Loss: {running_loss / len(train_dataset)}")
    
    # 验证
    model.eval()
    correct = 0
    total = 0
    with torch.no_grad():
        for images, labels in val_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()
    
    print(f"Validation Accuracy: {100 * correct / total:.2f}%")

💾 第六步:保存模型

torch.save(model.state_dict(), 'flowers102_resnet50.pth')
print("Model saved.")

📈 可选:可视化训练过程(Matplotlib)

可将每个 epoch 的 loss 和 accuracy 存储在一个列表中,并在训练结束后绘制图表。


好的,下面是扩展后的完整代码示例,包括使用 imagelabels.matsetid.mat 文件构建数据集、多GPU训练支持、TensorBoard可视化、混淆矩阵分析以及测试集预测与提交文件生成。

1. 加载 .mat 文件

首先,我们需要加载 .mat 文件以获取图像标签和数据集划分信息。这可以通过 scipy.io.loadmat 实现:

import scipy.io as sio

def load_mat_data(mat_file_path):
    mat_data = sio.loadmat(mat_file_path)
    return mat_data

2. 更新 Dataset 类以利用 .mat 文件

Flowers102Dataset 中添加对 .mat 文件的支持:

class Flowers102Dataset(Dataset):
    def __init__(self, root_dir, list_file=None, transform=None, label_file='imagelabels.mat', set_file='setid.mat'):
        self.root_dir = root_dir
        self.transform = transform
        labels_mat = load_mat_data(os.path.join(root_dir, label_file))
        setid_mat = load_mat_data(os.path.join(root_dir, set_file))

        if list_file is None:
            # 根据 setid.mat 分割数据集
            self.image_paths, self.labels = self._load_from_setid(setid_mat, labels_mat)
        else:
            self.image_paths, self.labels = self._load_list(os.path.join(root_dir, list_file), labels_mat)

    def _load_list(self, file_path, labels_mat):
        image_paths = []
        labels = []
        with open(file_path, 'r') as f:
            for line in f:
                img_name, label = line.strip().split()
                image_paths.append(os.path.join(self.root_dir, 'jpg', img_name))
                labels.append(int(label) - 1)  # 标签从0开始
        return image_paths, labels

    def _load_from_setid(self, setid_mat, labels_mat):
        ids = {'train': setid_mat['trnid'][0], 'val': setid_mat['valid'][0], 'test': setid_mat['tstid'][0]}
        image_paths = []
        labels = []
        for idx in ids['train']:
            image_paths.append(os.path.join(self.root_dir, 'jpg', f'image_{idx:05}.jpg'))
            labels.append(labels_mat['labels'][0][idx-1] - 1)
        return image_paths, labels
    # ... 其他方法保持不变

3. 多GPU训练支持

确保模型可以在多个GPU上运行:

if torch.cuda.device_count() > 1:
    print(f"Let's use {torch.cuda.device_count()} GPUs!")
    model = nn.DataParallel(model)

4. TensorBoard 可视化

集成 TensorBoard 进行可视化:

from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter('runs/flowers102_experiment')

# 在训练循环中添加以下代码:
for epoch in range(num_epochs):
    # ...
    writer.add_scalar('training loss', running_loss / len(train_dataset), epoch)
    writer.add_scalar('validation accuracy', 100 * correct / total, epoch)

5. 混淆矩阵分析

在验证阶段计算并绘制混淆矩阵:

from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt

def plot_confusion_matrix(cm, classes, normalize=False, title='Confusion matrix', cmap=plt.cm.Blues):
    plt.figure(figsize=(10,10))
    sns.heatmap(cm, annot=True, fmt='d' if not normalize else '.2f', cmap=cmap)
    plt.title(title)
    plt.ylabel('True label')
    plt.xlabel('Predicted label')
    plt.xticks(range(len(classes)), classes, rotation=90)
    plt.yticks(range(len(classes)), classes, rotation=0)
    plt.show()

# 在验证后:
model.eval()
all_labels = []
all_preds = []
with torch.no_grad():
    for images, labels in val_loader:
        images, labels = images.to(device), labels.to(device)
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        all_labels.extend(labels.cpu().numpy())
        all_preds.extend(predicted.cpu().numpy())

cm = confusion_matrix(all_labels, all_preds)
plot_confusion_matrix(cm, classes=[str(i) for i in range(102)])

6. 测试集预测与提交文件生成

根据 setid.mat 中的测试集ID进行预测,并保存结果:

def generate_submission(model, test_ids, output_path='submission.csv'):
    model.eval()
    results = []
    for idx in test_ids:
        image_path = os.path.join(root_dir, 'jpg', f'image_{idx:05}.jpg')
        image = Image.open(image_path).convert('RGB')
        if transform_val:
            image = transform_val(image).unsqueeze(0).to(device)
        
        with torch.no_grad():
            output = model(image)
            _, predicted = torch.max(output.data, 1)
            results.append((idx, predicted.item() + 1))  # 调整回原始标签编号

    with open(output_path, 'w') as f:
        for idx, label in results:
            f.write(f'{idx},{label}\n')

# 使用时:
test_ids = setid_mat['tstid'][0]
generate_submission(model, test_ids)
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐