12.12深度学习_CNN_项目实战

基于CNN的AnimalTriClassifier

关于项目实现的文档说明书,三个要素:数据、模型、训练

1、项目简介

关于项目的基本介绍。

本项目实现的是对猫科动物的划分,划分的物种有猫、狗、野生三种分类,属于小颗粒度分类

  • 大颗粒度分类:以物种作为分类,比如飞机、青蛙、狗、猫、马、鹿等。
  • 实体颗粒度分类:具体到具体的人,比如指纹识别、人脸识别等具体的个体,具体的实体

1.1 项目名称

​ 基于CNN的AnimalTriClassifie

1.2 项目简介

​ 本项目旨在使用卷积神经网络(CNN)进行图像分类任务。我们将使用 LeNet5(衍生) 模型来训练一个可以区分猫、狗和野生动物的分类器。项目中包括了数据预处理、模型训练、测试、验证以及单张图片推理等功能。

2、数据

公开的数据集

2.1 公开数据集

Animal Faces

2.3 数据增强

提升模型的泛化能力和鲁棒性。

    # 数据预处理和加载
    transform = transforms.Compose([
        # transforms.RandomVerticalFlip(),
        # transforms.RandomRotation(degrees=(0, 180)),
        # transforms.RandomHorizontalFlip(),  # 随机水平翻转
        # transforms.RandomRotation(10),
        # transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),  
        transforms.ToTensor(),
        transforms.Resize((64, 64)),
        transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225]) ,
        transforms.RandomRotation(degrees=(0, 180)),
        transforms.RandomInvert(), # 随机反转变换,
        transforms.RandomAffine(degrees=(30, 70), translate=(0.1, 0.3), scale=(0.5, 0.75)),
        ])

3. 神经网络

手写LeNets5

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

class LeNet5(nn.Module):
    def __init__(self, num_classes=3):
        super(LeNet5, self).__init__()
        # 第一层卷积层,输入通道为3,输出通道为16,卷积核大小为5x5,步幅为1,填充为2
        self.layer1 = nn.Sequential(
            nn.Conv2d(3, 16, kernel_size=5, stride=1, padding=2),  # 输出大小: (64 + 2*2 - 5)/1 + 1 = 64
            nn.ReLU(),  # 使用 ReLU 激活函数
            nn.AvgPool2d(kernel_size=2, stride=2)  # 输出大小: 64 / 2 = 32
        )
        # 第二层卷积层,输入通道为16,输出通道为32,卷积核大小为5x5,步幅为1,填充为2
        self.layer2 = nn.Sequential(
            nn.Conv2d(16, 32, kernel_size=5, stride=1, padding=2),  # 输出大小: (32 + 2*2 - 5)/1 + 1 = 32
            nn.ReLU(),  # 使用 ReLU 激活函数
            nn.AvgPool2d(kernel_size=2, stride=2)  # 输出大小: 32 / 2 = 16
        )
        # 第三层卷积层,输入通道为32,输出通道为64,卷积核大小为5x5,步幅为1,填充为2
        self.layer3 = nn.Sequential(
            nn.Conv2d(32, 64, kernel_size=5, stride=1, padding=2),  # 输出大小: (16 + 2*2 - 5)/1 + 1 = 16
            nn.ReLU(),  # 使用 ReLU 激活函数
            nn.AvgPool2d(kernel_size=2, stride=2)  # 输出大小: 16 / 2 = 8
        )
        # 全连接层
        self.fc1 = nn.Linear(64 * 8 * 8, 120)  # 输入大小: 64 * 8 * 8
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, num_classes)

    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = self.layer3(out)
        out = out.reshape(out.size(0), -1)  # 展平
        out = F.relu(self.fc1(out))  # 使用 ReLU 激活函数
        out = F.relu(self.fc2(out))  # 使用 ReLU 激活函数
        out = self.fc3(out)
        return out

# 创建模型实例
model = LeNet5(num_classes=3)

4. 模型训练

def train():
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    # 数据预处理和加载
    transform = transforms.Compose([
        transforms.RandomVerticalFlip(),
        # transforms.RandomRotation(degrees=(0, 180)),
        # transforms.RandomHorizontalFlip(),  # 随机水平翻转
        # transforms.RandomRotation(10),
        transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),  
        transforms.ToTensor(),
        transforms.Resize((64, 64)),
        transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225]) ,
        transforms.RandomRotation(degrees=(0, 180)),
        transforms.RandomInvert(), # 随机反转变换,
        transforms.RandomAffine(degrees=(30, 70), translate=(0.1, 0.3), scale=(0.5, 0.75)),
        ])

    # 检查数据集路径是否存在
    train_path = os.path.join(data_path, 'train')
    if not os.path.exists(train_path):
        raise FileNotFoundError(f"数据集路径不存在: {
     
     train_path}")

    # 加载整个数据集
    full_dataset = ImageFolder(root=train_path, transform=transform)
    print("分类列表:", full_dataset.classes)
    print("分类和索引的对应关系:", full_dataset.class_to_idx)

    # 分割数据集为训练集和测试集
    train_ratio = 0.7
    train_size = int(train_ratio * len(full_dataset))
    test_size = len(full_dataset) - train_size
    train_dataset, test_dataset = random_split(full_dataset, [train_size, test_size])

    # 模型准备
    net = LeNet5(num_classes=len(full_dataset.classes)).to(device)  # 使用 LeNet5 模型
    state_dict = torch.load(pth_path)
    net.load_state_dict(state_dict)
    net.train()

    # 保存网络结构到tensorboard
    writer.add_graph(net, torch.randn(1, 3, 64, 64).to(device))  # 添加模型的计算图

    # 训练设置
    epochs = 10
    batch_size = 64
    criterion = nn.CrossEntropyLoss(reduction="sum")
    optimizer = optim.Adam(net.parameters(), lr=0.0001)

    train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
    test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

    for epoch in range(epochs):
        start_time = time.time()
        accuracy = 0
        total_loss = 0

        # 使用 tqdm 显示进度条
        for i, (x, y) in enumerate(tqdm(train_loader, desc=f"Epoch {
     
     epoch+1}/{
     
     epochs}")):
            x, y = x.to(device), y.to(device)
            optimizer.zero_grad()
            yhat = net(x)
            loss = criterion(yhat, y)
            loss.backward()
            optimizer.step()

            accuracy += torch.sum(torch.argmax(yhat, dim=1) == y).item()
            total_loss += loss.item()

            # 每 1 个批次保存一次图像
            if i % 1 == 0:
                img_grid = vutils.make_grid(x, normalize=True, nrow=8)  # 生成图像网格
                writer.add_image(f"r_m_{
     
     epoch}_{
     
     i * 1}", img_grid, epoch * len(train_dataset) + i)

        print(
            f"Epoch {
     
     epoch+1}/{
     
     epochs} - Time: {
     
     time.time() - start_time:.2f}s, Accuracy: {
     
     accuracy / len(train_dataset):.4f}, Loss: {
     
     total_loss / len(train_dataset):.4f}")
        writer.add_scalar("Loss/train", total_loss / len(train_dataset), epoch)
        writer.add_scalar("Accuracy/train", accuracy / len(t
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值