垃圾分类项目1.0

垃圾分类项目1.0

前言

在深度学习中实现垃圾分类的主要步骤包括数据准备、模型构建、模型训练、模型评估和部署。以下是每个步骤的详细说明:
一、数据准备:
数据收集:收集包含不同类别垃圾的图像数据。
数据清洗与标注:清洗数据以去除无关或重复的图像,并对每个图像进行标注,确保每张图片都分配到正确的垃圾类别。
数据增强:使用数据增强技术(如旋转、裁剪、缩放等)增加数据集的多样性,减少模型过拟合的风险。
数据划分:将数据集划分为训练集、验证集和测试集。
二、模型构建:
选择模型架构:选择合适的神经网络架构(如卷积神经网络CNN、残差网络ResNet等)用于分类任务。
模型定义:使用深度学习框架(如PyTorch、TensorFlow等)定义模型的各层结构和参数。
模型训练:
定义损失函数和优化器:选择适当的损失函数(如交叉熵损失)和优化器(如Adam、SGD等)。
训练循环:编写训练循环代码,在训练集中迭代模型,并根据损失函数最小化的目标调整模型参数。
模型检查点:在训练过程中定期保存模型检查点,以防止训练中断时丢失进度。
三、模型评估:
验证集评估:在每个训练周期后使用验证集评估模型性能,调整超参数以提高模型准确性。
测试集评估:在最终训练结束后,在测试集中评估模型的性能,确保模型在未见过的数据上也能表现良好。

一、数据准备

首先由于刚开始学习,先做一个简单的垃圾分类的小项目,所以跳过数据的清洗和增强,我们对数据进行划分,划为训练集和测试集。

import os
import random

train_ratio = 0.9
rootdata = "D:/Administrator/Desktop/all/all"

train_list, test_list = [], []

class_flag = 0  # 从0开始标记类别

# 遍历根目录
for root, dirs, files in os.walk(rootdata):
    # 遍历每个类别文件夹中的所有文件
    for file in files:
        file_path = os.path.join(root, file)
        # 根据训练和测试比例划分数据
        if random.random() < train_ratio:
            train_list.append(f"{file_path}\t{class_flag}\n")
        else:
            test_list.append(f"{file_path}\t{class_flag}\n")

    # 处理完一个文件夹中的所有文件后,切换到下一个类别
    class_flag += 1

# 打乱列表顺序
random.shuffle(train_list)
random.shuffle(test_list)

# 将训练和测试数据写入文件
with open('train.txt', 'w', encoding='UTF-8') as f:
    f.writelines(train_list)

with open('test.txt', 'w', encoding='UTF-8') as f:
    f.writelines(test_list)

1.变量定义:
train_ratio: 定义训练集占总数据的比例。
rootdata :是数据集的根目录。
train_list 和 test_list: 分别是存储训练集和测试集的文件路径及其标签。
class_flag: 用于标记当前类别,从0开始。
2.数据划分:
使用 os.walk() 遍历 rootdata 目录及其子目录。
对每个文件,根据 train_ratio 将文件路径和类别标签添加到 train_list 或 test_list。
3.数据打乱:
使用 random.shuffle() 打乱训练集和测试集的顺序,以确保训练过程中数据的随机性。
(作用:防止过拟合,打乱数据可以防止模型过拟合于某个特定的顺序模式。如果数据集中存在某种模式(例如,所有相同类别的图像都集中在一起),模型可能会过度拟合这种模式。通过打乱数据,模型会在训练过程中看到更广泛的组合,从而减少过拟合的风险。)
假设你的数据集中有不同类别的垃圾图片,按照类别存储在文件夹中。如果不打乱数据,模型可能会首先看到所有类别1的图片,然后是类别2的图片,依此类推。这种情况下,模型在初期会集中学习某一类别的特征,而忽略其他类别的特征,导致模型的初期学习效率低下。
通过打乱数据,模型在每个训练周期中都会看到不同类别的混合数据,这样可以帮助模型同时学习不同类别的特征,提高训练效率和模型性能。
4.写入文件:
将训练集和测试集的数据分别写入 train.txt 和 test.txt 文件中

二、模型构建

2.1神经网络构建

在model文件夹下创建net文件,开始搭建自己的网络结构

import torch
import torch.nn as nn
import torch.nn.functional as F

class simpleconv3(nn.Module):
    def __init__(self, num_classes):
        super(simpleconv3, self).__init__()
        self.conv1 = nn.Conv2d(3, 12, 3, 2)  # 输入图片大小为3*48*48,输出特征图大小为12*23*23,卷积核大小为3*3,步长为2
        self.bn1 = nn.BatchNorm2d(12)
        self.conv2 = nn.Conv2d(12, 24, 3, 2)  # 输入图片大小为12*23*23,输出特征图大小为24*11*11,卷积核大小为3*3,步长为2
        self.bn2 = nn.BatchNorm2d(24)
        self.conv3 = nn.Conv2d(24, 48, 3, 2)  # 输入图片大小为24*11*11,输出特征图大小为48*5*5,卷积核大小为3*3,步长为2
        self.bn3 = nn.BatchNorm2d(48)
        self.fc1 = nn.Linear(48 * 5 * 5, 1200)  # 输入向量长为48*5*5=1200,输出向量长为1200
        self.fc2 = nn.Linear(1200, 128)  # 输入向量长为1200,输出向量长为128
        self.fc3 = nn.Linear(128, num_classes)  # 输入向量长为128,输出向量长为num_classes,等于类别数

    def forward(self, x):
        x = F.relu(self.bn1(self.conv1(x)))
        x = F.relu(self.bn2(self.conv2(x)))
        x = F.relu(self.bn3(self.conv3(x)))
        x = x.view(x.size(0), -1)  # 动态调整批次大小
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

1.定义模型结构:
simpleconv3类继承自nn.Module,在其构造函数__init__中定义了模型的层次结构,包括卷积层、批量归一化层和全连接层。
conv1、conv2、conv3是三层卷积层,分别处理输入图像并提取特征。
bn1、bn2、bn3是对应的批量归一化层,帮助稳定和加速训练过程。
fc1、fc2、fc3是全连接层,负责将卷积特征转换为最终的输出类别。
2.前向传播(forward pass):
在forward方法中,数据依次通过卷积、批量归一化、ReLU激活函数和全连接层。
x.view(x.size(0), -1)将卷积层的输出展平成一维向量,以便传递给全连接层。

2.2数据加载器

数据加载器的作用
1.批量加载数据:
数据加载器可以将数据集分成多个小批次(batch),在训练和测试过程中逐批加载数据。这对于内存管理和计算效率非常重要。

2.打乱数据:
训练时打乱数据(shuffle)可以防止模型在训练过程中对数据的顺序产生依赖,从而提高模型的泛化能力。

3.并行加载数据:
数据加载器支持多线程并行加载数据,从而加快数据读取速度,减少数据加载时间对训练过程的影响。

4.数据预处理:
数据加载器可以与数据转换操作(如数据增强、标准化等)配合使用,在每次加载数据时对数据进行预处理。

import os
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
from PIL import Image, UnidentifiedImageError

class CustomDataset(Dataset):
    def __init__(self, txt_file, transform=None):
        self.img_labels = []
        with open(txt_file, 'r') as file:
            for line in file:
                path, label = line.strip().split('\t')
                # 确保路径格式正确
                path = os.path.normpath(path)
                # 只添加有效的图像路径
                if self._is_image_file(path):
                    self.img_labels.append((path, int(label)))
        self.transform = transform

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

    def __getitem__(self, idx):
        img_path, label = self.img_labels[idx]
        try:
            image = Image.open(img_path).convert('RGB')  # 确保图像是 RGB 模式
        except (UnidentifiedImageError, IOError) as e:
            print(f"Error loading image {img_path}: {e}")
            # 如果遇到错误,可以选择返回一个空图像或某种默认值
            image = Image.new('RGB', (48, 48))  # 创建一个指定大小的黑色图像
        if self.transform:
            image = self.transform(image)
        return image, label

    def _is_image_file(self, path):
        # 判断文件是否是图像文件
        IMAGE_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff'}
        return any(path.lower().endswith(ext) for ext in IMAGE_EXTENSIONS)

class TestDataset(Dataset):
    def __init__(self, txt_file, transform=None):
        self.img_paths = []
        with open(txt_file, 'r') as file:
            for line in file:
                path = line.strip()
                # 确保路径格式正确
                path = os.path.normpath(path)
                self.img_paths.append(path)
        self.transform = transform

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

    def __getitem__(self, idx):
        img_path = self.img_paths[idx]
        try:
            image = Image.open(img_path).convert('RGB')  # 确保图像是 RGB 模式
        except (UnidentifiedImageError, IOError) as e:
            print(f"Error loading image {img_path}: {e}")
            # 如果遇到错误,可以选择返回一个空图像或某种默认值
            image = Image.new('RGB', (48, 48))  # 创建一个指定大小的黑色图像
        if self.transform:
            image = self.transform(image)
        return image

# 数据转换操作
transform = transforms.Compose([
    transforms.Resize((48, 48)),
    transforms.ToTensor(),
])

# 创建训练集和测试集数据集及数据加载器
train_dataset = CustomDataset(txt_file=r'E:\deep lerning\lajifenlei\train.txt', transform=transform)
train_dataloader = DataLoader(train_dataset, batch_size=32, shuffle=True)

test_dataset = CustomDataset(txt_file=r'E:\deep lerning\lajifenlei\test.txt', transform=transform)
test_dataloader = DataLoader(test_dataset, batch_size=32, shuffle=False)


三、模型训练

创建train.py文件
以下是完整的训练流程:
1.导入必要的模块
2.定义训练参数
3.创建模型实例
4.定义损失函数和优化器
5.训练模型

import torch
from torch import nn
import torch.optim as optim
from model.net import simpleconv3
from dataset.dataset import train_dataloader


def train_model(model, dataloader, num_epochs=5, checkpoint_interval=1, final_model_path="final_model.pth"):
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    model.to(device)

    for epoch in range(num_epochs):
        model.train()
        running_loss = 0.0

        for images, labels in dataloader:
            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()

        avg_loss = running_loss / len(dataloader)
        print(f"Epoch [{epoch + 1}/{num_epochs}], Loss: {avg_loss:.4f}")

        # 保存检查点
       # if (epoch + 1) % checkpoint_interval == 0:
            #save_model(model, f"model_checkpoint_epoch_{epoch + 1}.pth")

    # 在训练完成后保存最终模型
    save_model(model, final_model_path)
    print("Training Finished")


def save_model(model, path):
    torch.save(model.state_dict(), path)
    print(f"Model saved to {path}")


def load_model(model, path):
    model.load_state_dict(torch.load(path))
    model.eval()
    print(f"Model weights loaded from {path}")


# 示例用法
if __name__ == "__main__":
    model = simpleconv3(num_classes=50)
    train_model(model, train_dataloader, num_epochs=3, checkpoint_interval=1, final_model_path="final_model.pth")

注意:
from model.net import simpleconv3是将同目录下的model文件夹下的model文件的simpleconv3模型导入,from dataset.dataset import train_dataloadershi从 dataset 模块中的 dataset 文件中导入 train_dataloader 对象。

四、模型评估

from model.net import simpleconv3
from dataset.dataset import test_dataloader
import torch

# 定义设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

def evaluate_model(model, dataloader):
    model.to(device)  # 确保模型在正确的设备上
    model.eval()
    correct = 0
    total = 0
    with torch.no_grad():
        for images, labels in dataloader:
            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'Accuracy of the network on the test images: {100 * correct // total}%')

def load_model(model, file_path):
    model.load_state_dict(torch.load(file_path, map_location=device))
    model.to(device)  # 确保模型在正确的设备上
    model.eval()  # 设置模型为评估模式
    print(f"Model weights loaded from {file_path}")

# 实例化模型
model = simpleconv3(num_classes=50)

# 加载模型权重
load_model(model, 'final_model.pth')

# 评估模型
evaluate_model(model, test_dataloader)

应注意的是model = simpleconv3(num_classes=50)中num_classes应为具体的类数

五、单图片预测

import torch
from PIL import Image
from torchvision import transforms
from model.net import simpleconv3

# 定义设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 加载模型
def load_model(model, file_path):
    model.load_state_dict(torch.load(file_path, map_location=device))
    model.to(device)  # 确保模型在正确的设备上
    model.eval()  # 设置模型为评估模式
    print(f"Model weights loaded from {file_path}")

# 图像预处理
transform = transforms.Compose([
    transforms.Resize((48, 48)),
    transforms.ToTensor(),
])

def predict_single_image(model, image_path):
    # 加载并预处理图像
    image = Image.open(image_path).convert('RGB')
    image = transform(image).unsqueeze(0)  # 增加一个维度以适应批处理格式
    
    # 将图像移到设备上
    image = image.to(device)
    
    # 模型预测
    with torch.no_grad():
        output = model(image)
        _, predicted = torch.max(output.data, 1)
    
    return predicted.item()

# 实例化模型
model = simpleconv3(num_classes=55)

# 加载模型权重
load_model(model, 'final_model.pth')

# 对单个图像进行预测
image_path = '"D:\Administrator\Desktop\all\all\1\img_332.jpg"'
prediction = predict_single_image(model, image_path)
print(f'Predicted class for the image: {prediction}')

运行该文件可对单图像进行预测

  • 26
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值