Pytorch自定义模型实现猫狗分类

简介: Pytorch自定义模型实现猫狗分类

摘要

本例采用猫狗大战的部分数据作为数据集,模型是自定义的模型。

训练

  • 1、构建数据集

在data文件夹下面新家train和val文件夹,分别在train和val文件夹下面新家cat和dog文件夹,并将图片放进去。如图:

tt.png

2、导入库

# 导入库

import torch.nn.functional as F

import torch.optim as optim

import torch

import torch.nn as nn

import torch.nn.parallel

import torch.optim

import torch.utils.data

import torch.utils.data.distributed

import torchvision.transforms as transforms

import torchvision.datasets as datasets

3、设置超参数

# 设置超参数

BATCH_SIZE = 20

EPOCHS = 10

DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

4、图像处理与图像增强

# 数据预处理

transform = transforms.Compose([

   transforms.Resize(100),

   transforms.RandomVerticalFlip(),

   transforms.RandomCrop(50),

   transforms.RandomResizedCrop(150),

   transforms.ColorJitter(brightness=0.5, contrast=0.5, hue=0.5),

   transforms.ToTensor(),

   transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])

])

5、读取数据和导入数据

# 读取数据

dataset_train = datasets.ImageFolder('data/train', transform)

print(dataset_train.imgs)

# 对应文件夹的label

print(dataset_train.class_to_idx)

dataset_test = datasets.ImageFolder('data/val', transform)

# 对应文件夹的label

print(dataset_test.class_to_idx)

# 导入数据

train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True)

test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE, shuffle=True)

6、定义网络模型

# 定义网络

class ConvNet(nn.Module):

   def __init__(self):

       super(ConvNet, self).__init__()

       self.conv1 = nn.Conv2d(3, 32, 3)

       self.max_pool1 = nn.MaxPool2d(2)

       self.conv2 = nn.Conv2d(32, 64, 3)

       self.max_pool2 = nn.MaxPool2d(2)

       self.conv3 = nn.Conv2d(64, 64, 3)

       self.conv4 = nn.Conv2d(64, 64, 3)

       self.max_pool3 = nn.MaxPool2d(2)

       self.conv5 = nn.Conv2d(64, 128, 3)

       self.conv6 = nn.Conv2d(128, 128, 3)

       self.max_pool4 = nn.MaxPool2d(2)

       self.fc1 = nn.Linear(4608, 512)

       self.fc2 = nn.Linear(512, 1)

   def forward(self, x):

       in_size = x.size(0)

       x = self.conv1(x)

       x = F.relu(x)

       x = self.max_pool1(x)

       x = self.conv2(x)

       x = F.relu(x)

       x = self.max_pool2(x)

       x = self.conv3(x)

       x = F.relu(x)

       x = self.conv4(x)

       x = F.relu(x)

       x = self.max_pool3(x)

       x = self.conv5(x)

       x = F.relu(x)

       x = self.conv6(x)

       x = F.relu(x)

       x = self.max_pool4(x)

       # 展开

       x = x.view(in_size, -1)

       x = self.fc1(x)

       x = F.relu(x)

       x = self.fc2(x)

       x = torch.sigmoid(x)

       return x

modellr = 1e-4

# 实例化模型并且移动到GPU

model = ConvNet().to(DEVICE)

# 选择简单暴力的Adam优化器,学习率调低

optimizer = optim.Adam(model.parameters(), lr=modellr)

7、调整学习率

def adjust_learning_rate(optimizer, epoch):

   """Sets the learning rate to the initial LR decayed by 10 every 30 epochs"""

   modellrnew = modellr * (0.1 ** (epoch // 5))

   print("lr:",modellrnew)

   for param_group in optimizer.param_groups:

       param_group['lr'] = modellrnew

8、定义训练与验证方法

# 定义训练过程

def train(model, device, train_loader, optimizer, epoch):

   model.train()

   for batch_idx, (data, target) in enumerate(train_loader):

       data, target = data.to(device), target.to(device).float().unsqueeze(1)

       optimizer.zero_grad()

       output = model(data)

       # print(output)

       loss = F.binary_cross_entropy(output, target)

       loss.backward()

       optimizer.step()

       if (batch_idx + 1) % 10 == 0:

           print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(

               epoch, (batch_idx + 1) * len(data), len(train_loader.dataset),

                      100. * (batch_idx + 1) / len(train_loader), loss.item()))

# 定义测试过程

def val(model, device, test_loader):

   model.eval()

   test_loss = 0

   correct = 0

   with torch.no_grad():

       for data, target in test_loader:

           data, target = data.to(device), target.to(device).float().unsqueeze(1)

           output = model(data)

           # print(output)

           test_loss += F.binary_cross_entropy(output, target, reduction='mean').item()  # 将一批的损失相加

           pred = torch.tensor([[1] if num[0] >= 0.5 else [0] for num in output]).to(device)

           correct += pred.eq(target.long()).sum().item()

       print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(

           test_loss, correct, len(test_loader.dataset),

           100. * correct / len(test_loader.dataset)))

9、训练并保存模型

# 训练

for epoch in range(1, EPOCHS + 1):

   adjust_learning_rate(optimizer, epoch)

   train(model, DEVICE, train_loader, optimizer, epoch)

   val(model, DEVICE, test_loader)

torch.save(model, 'model.pth')

完整代码:

# 导入库

import torch.nn.functional as F

import torch.optim as optim

import torch

import torch.nn as nn

import torch.nn.parallel

import torch.optim

import torch.utils.data

import torch.utils.data.distributed

import torchvision.transforms as transforms

import torchvision.datasets as datasets

# 设置超参数

BATCH_SIZE = 20

EPOCHS = 10

DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# 数据预处理

transform = transforms.Compose([

   transforms.Resize(100),

   transforms.RandomVerticalFlip(),

   transforms.RandomCrop(50),

   transforms.RandomResizedCrop(150),

   transforms.ColorJitter(brightness=0.5, contrast=0.5, hue=0.5),

   transforms.ToTensor(),

   transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])

])

# 读取数据

dataset_train = datasets.ImageFolder('data/train', transform)

print(dataset_train.imgs)

# 对应文件夹的label

print(dataset_train.class_to_idx)

dataset_test = datasets.ImageFolder('data/val', transform)

# 对应文件夹的label

print(dataset_test.class_to_idx)

# 导入数据

train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True)

test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE, shuffle=True)

# 定义网络

class ConvNet(nn.Module):

   def __init__(self):

       super(ConvNet, self).__init__()

       self.conv1 = nn.Conv2d(3, 32, 3)

       self.max_pool1 = nn.MaxPool2d(2)

       self.conv2 = nn.Conv2d(32, 64, 3)

       self.max_pool2 = nn.MaxPool2d(2)

       self.conv3 = nn.Conv2d(64, 64, 3)

       self.conv4 = nn.Conv2d(64, 64, 3)

       self.max_pool3 = nn.MaxPool2d(2)

       self.conv5 = nn.Conv2d(64, 128, 3)

       self.conv6 = nn.Conv2d(128, 128, 3)

       self.max_pool4 = nn.MaxPool2d(2)

       self.fc1 = nn.Linear(4608, 512)

       self.fc2 = nn.Linear(512, 1)

   def forward(self, x):

       in_size = x.size(0)

       x = self.conv1(x)

       x = F.relu(x)

       x = self.max_pool1(x)

       x = self.conv2(x)

       x = F.relu(x)

       x = self.max_pool2(x)

       x = self.conv3(x)

       x = F.relu(x)

       x = self.conv4(x)

       x = F.relu(x)

       x = self.max_pool3(x)

       x = self.conv5(x)

       x = F.relu(x)

       x = self.conv6(x)

       x = F.relu(x)

       x = self.max_pool4(x)

       # 展开

       x = x.view(in_size, -1)

       x = self.fc1(x)

       x = F.relu(x)

       x = self.fc2(x)

       x = torch.sigmoid(x)

       return x

modellr = 1e-4

# 实例化模型并且移动到GPU

model = ConvNet().to(DEVICE)

# 选择简单暴力的Adam优化器,学习率调低

optimizer = optim.Adam(model.parameters(), lr=modellr)

def adjust_learning_rate(optimizer, epoch):

   """Sets the learning rate to the initial LR decayed by 10 every 30 epochs"""

   modellrnew = modellr * (0.1 ** (epoch // 5))

   print("lr:",modellrnew)

   for param_group in optimizer.param_groups:

       param_group['lr'] = modellrnew

# 定义训练过程

def train(model, device, train_loader, optimizer, epoch):

   model.train()

   for batch_idx, (data, target) in enumerate(train_loader):

       data, target = data.to(device), target.to(device).float().unsqueeze(1)

       optimizer.zero_grad()

       output = model(data)

       # print(output)

       loss = F.binary_cross_entropy(output, target)

       loss.backward()

       optimizer.step()

       if (batch_idx + 1) % 10 == 0:

           print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(

               epoch, (batch_idx + 1) * len(data), len(train_loader.dataset),

                      100. * (batch_idx + 1) / len(train_loader), loss.item()))

# 定义测试过程

def val(model, device, test_loader):

   model.eval()

   test_loss = 0

   correct = 0

   with torch.no_grad():

       for data, target in test_loader:

           data, target = data.to(device), target.to(device).float().unsqueeze(1)

           output = model(data)

           # print(output)

           test_loss += F.binary_cross_entropy(output, target, reduction='mean').item()  # 将一批的损失相加

           pred = torch.tensor([[1] if num[0] >= 0.5 else [0] for num in output]).to(device)

           correct += pred.eq(target.long()).sum().item()

       print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(

           test_loss, correct, len(test_loader.dataset),

           100. * correct / len(test_loader.dataset)))

# 训练

for epoch in range(1, EPOCHS + 1):

   adjust_learning_rate(optimizer, epoch)

   train(model, DEVICE, train_loader, optimizer, epoch)

   val(model, DEVICE, test_loader)

torch.save(model, 'model.pth')

测试

完整代码:

from __future__ import print_function, division

from PIL import Image

from torchvision import transforms

import torch.nn.functional as F

import torch

import torch.nn as nn

import torch.nn.parallel

# 定义网络

class ConvNet(nn.Module):

   def __init__(self):

       super(ConvNet, self).__init__()

       self.conv1 = nn.Conv2d(3, 32, 3)

       self.max_pool1 = nn.MaxPool2d(2)

       self.conv2 = nn.Conv2d(32, 64, 3)

       self.max_pool2 = nn.MaxPool2d(2)

       self.conv3 = nn.Conv2d(64, 64, 3)

       self.conv4 = nn.Conv2d(64, 64, 3)

       self.max_pool3 = nn.MaxPool2d(2)

       self.conv5 = nn.Conv2d(64, 128, 3)

       self.conv6 = nn.Conv2d(128, 128, 3)

       self.max_pool4 = nn.MaxPool2d(2)

       self.fc1 = nn.Linear(4608, 512)

       self.fc2 = nn.Linear(512, 1)

   def forward(self, x):

       in_size = x.size(0)

       x = self.conv1(x)

       x = F.relu(x)

       x = self.max_pool1(x)

       x = self.conv2(x)

       x = F.relu(x)

       x = self.max_pool2(x)

       x = self.conv3(x)

       x = F.relu(x)

       x = self.conv4(x)

       x = F.relu(x)

       x = self.max_pool3(x)

       x = self.conv5(x)

       x = F.relu(x)

       x = self.conv6(x)

       x = F.relu(x)

       x = self.max_pool4(x)

       # 展开

       x = x.view(in_size, -1)

       x = self.fc1(x)

       x = F.relu(x)

       x = self.fc2(x)

       x = torch.sigmoid(x)

       return x

# 模型存储路径

model_save_path = 'model.pth'

# ------------------------ 加载数据 --------------------------- #

# Data augmentation and normalization for training

# Just normalization for validation

# 定义预训练变换

# 数据预处理

transform_test = transforms.Compose([

   transforms.Resize(100),

   transforms.RandomVerticalFlip(),

   transforms.RandomCrop(50),

   transforms.RandomResizedCrop(150),

   transforms.ColorJitter(brightness=0.5, contrast=0.5, hue=0.5),

   transforms.ToTensor(),

   transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])

])

class_names = ['cat', 'dog']  # 这个顺序很重要,要和训练时候的类名顺序一致

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

# ------------------------ 载入模型并且训练 --------------------------- #

model = torch.load(model_save_path)

model.eval()

# print(model)

image_PIL = Image.open('dog.12.jpg')

#

image_tensor = transform_test(image_PIL)

# 以下语句等效于 image_tensor = torch.unsqueeze(image_tensor, 0)

image_tensor.unsqueeze_(0)

# 没有这句话会报错

image_tensor = image_tensor.to(device)

out = model(image_tensor)

pred = torch.tensor([[1] if num[0] >= 0.5 else [0] for num in out]).to(device)

print(class_names[pred])

运行结果:


tt.png


目录
相关文章
|
21天前
|
机器学习/深度学习 自然语言处理 PyTorch
【PyTorch实战演练】基于AlexNet的预训练模型介绍
【PyTorch实战演练】基于AlexNet的预训练模型介绍
113 0
|
21天前
|
机器学习/深度学习 算法 PyTorch
用PyTorch轻松实现二分类:逻辑回归入门
用PyTorch轻松实现二分类:逻辑回归入门
用PyTorch轻松实现二分类:逻辑回归入门
|
21天前
|
机器学习/深度学习 关系型数据库 MySQL
大模型中常用的注意力机制GQA详解以及Pytorch代码实现
GQA是一种结合MQA和MHA优点的注意力机制,旨在保持MQA的速度并提供MHA的精度。它将查询头分成组,每组共享键和值。通过Pytorch和einops库,可以简洁实现这一概念。GQA在保持高效性的同时接近MHA的性能,是高负载系统优化的有力工具。相关论文和非官方Pytorch实现可进一步探究。
208 4
|
21天前
|
机器学习/深度学习 数据采集 PyTorch
使用PyTorch解决多分类问题:构建、训练和评估深度学习模型
使用PyTorch解决多分类问题:构建、训练和评估深度学习模型
使用PyTorch解决多分类问题:构建、训练和评估深度学习模型
|
19天前
|
机器学习/深度学习 JSON PyTorch
图神经网络入门示例:使用PyTorch Geometric 进行节点分类
本文介绍了如何使用PyTorch处理同构图数据进行节点分类。首先,数据集来自Facebook Large Page-Page Network,包含22,470个页面,分为四类,具有不同大小的特征向量。为训练神经网络,需创建PyTorch Data对象,涉及读取CSV和JSON文件,处理不一致的特征向量大小并进行归一化。接着,加载边数据以构建图。通过`Data`对象创建同构图,之后数据被分为70%训练集和30%测试集。训练了两种模型:MLP和GCN。GCN在测试集上实现了80%的准确率,优于MLP的46%,展示了利用图信息的优势。
27 1
|
21天前
|
PyTorch 算法框架/工具 异构计算
pytorch 模型保存与加载
pytorch 模型保存与加载
16 0
|
21天前
|
PyTorch 算法框架/工具 Python
【pytorch框架】对模型知识的基本了解
【pytorch框架】对模型知识的基本了解
|
21天前
|
机器学习/深度学习 算法 PyTorch
PyTorch模型优化与调优:正则化、批归一化等技巧
【4月更文挑战第18天】本文探讨了PyTorch中提升模型性能的优化技巧,包括正则化(L1/L2正则化、Dropout)、批归一化、学习率调整策略和模型架构优化。正则化防止过拟合,Dropout提高泛化能力;批归一化加速训练并提升性能;学习率调整策略动态优化训练效果;模型架构优化涉及网络结构和参数的调整。这些方法有助于实现更高效的深度学习模型。
|
21天前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch与迁移学习:利用预训练模型提升性能
【4月更文挑战第18天】PyTorch支持迁移学习,助力提升深度学习性能。预训练模型(如ResNet、VGG)在大规模数据集(如ImageNet)训练后,可在新任务中加速训练,提高准确率。通过选择模型、加载预训练权重、修改结构和微调,可适应不同任务需求。迁移学习节省资源,但也需考虑源任务与目标任务的相似度及超参数选择。实践案例显示,预训练模型能有效提升小数据集上的图像分类任务性能。未来,迁移学习将继续在深度学习领域发挥重要作用。
|
21天前
|
机器学习/深度学习 PyTorch 调度
PyTorch进阶:模型保存与加载,以及断点续训技巧
【4月更文挑战第17天】本文介绍了PyTorch中模型的保存与加载,以及断点续训技巧。使用`torch.save`和`torch.load`可保存和加载模型权重和状态字典。保存模型时,可选择仅保存轻量级的状态字典或整个模型对象。加载时,需确保模型结构与保存时一致。断点续训需保存训练状态,包括epoch、batch index、optimizer和scheduler状态。中断后,加载这些状态以恢复训练,节省时间和资源。