1、数据集的准备
自己制作数据集比较麻烦,这里我们直接去网上找就行了
百度网盘可以得到数据:
链接: https://pan.baidu.com/s/12e1UTyERkZ9eZt4I9W7ZaA
提取码: rt7g
里面包含了训练集和测试集,需要的自行去获取
2、对数据进行resize
这里就直接上代码了,resize比较简单
我们用PLIL创建一个画布,画布的大小实际上就是我们需要的尺寸大小,然后等比例缩放原图,把resize后的图像融合到画布,这样就得到了我们需要的相同尺寸的图像
具体代码如下:
from PIL import Image
import os
def resize_img(img_path):
img = Image.open(img_path)
img_w, img_h = img.size
# 计算压缩比例:
ratio = min(100/img_w, 100/img_h)
new_w = int(img_w * ratio)
new_h = int(img_h * ratio)
# 等比例压缩图像
resized_img = img.resize((new_w, new_h), Image.ANTIALIAS)
# resized_img.show()
# 创建一个画布
canvas = Image.new('RGB', (100, 100), (255, 255, 255))
# 在画布上居中放置压缩好的图像
offset = ((100 - new_w) // 2, (100 - new_h) // 2)
# 融合在一起
canvas.paste(resized_img, offset)
return canvas
if __name__ == '__main__':
cat_root = r"原本猫的数据路径"
dog_root = r"原本狗的数据路径"
count = 1
for path in os.listdir(cat_root):
# 图像的具体路径
img_path = os.path.join(cat_root, path)
img = resize_img(img_path)
# 保存在我们当前项目的根目录下
img.save(rf"data\test\0\{path}")
3、对神经网络的具体构建
这里是我们需要的包
代码:
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
import os
import cv2
import numpy as np
import tqdm
在构建模型的时候,我们的神经网络是必不可少的,往往我们的神经网络的构建会决定后面模型的好坏程度,当然!不是全部原因
代码如下:
import torch
import torch.nn as nn
# 继承了nn.Module,这是构建PyTorch模型的基类
class Net_V1(nn.Module):
def __init__(self):
super().__init__()
# 定义神经网络的层结构
self.layer = nn.Sequential(
# in_features是输入特征数, out_features是输出特征数,
# 1 * 100 * 100 是我们图像的尺寸大小与通道数,后面的自行定义特征数,
# nn.LeakyRelu() 是我们的激活函数
nn.Linear(in_features=1 * 100 * 100, out_features=1024), nn.LeakyReLU(),
nn.Linear(in_features=1024, out_features=516), nn.LeakyReLU(),
nn.Linear(in_features=516, out_features=256), nn.LeakyReLU(),
nn.Linear(in_features=256, out_features=128), nn.LeakyReLU(),
nn.Linear(in_features=128, out_features=128), nn.LeakyReLU(),
nn.Linear(in_features=128, out_features=128), nn.LeakyReLU(),
nn.Linear(in_features=128, out_features=128), nn.LeakyReLU(),
nn.Linear(in_features=128, out_features=64), nn.LeakyReLU(),
nn.Linear(in_features=64, out_features=32), nn.LeakyReLU(),
nn.Linear(in_features=32, out_features=16), nn.LeakyReLU(),
# 最后的输出必须与我们需要的类别数相同,即二分类我们就是2
nn.Linear(in_features=16, out_features=2), # 最后一层输出2个值
nn.Sigmoid() # 最后一层的激活函数使用 Sigmoid
)
def forward(self, x):
# 前向传播函数,用于计算模型的输出
return self.layer(x)
4、对数据集的处理
我们自定义数据集。需要继承torch.utils.data.Dataset
在这一步我们会对数据的完整路径进行获取,包括标签,还会定义一个获取每个数据的函数
代码部分:
class MNIST_Dataset(Dataset):
def __init__(self, root, train=True):
# 父类的构造函数先实现
super().__init__()
self.dataset = []
# 判断是训练集还是测试集
train_or_test = "train" if train else "test"
path = f"{root}//{train_or_test}"
for label in os.listdir(path): # [0123456789]
img_path = f"{path}//{label}"
for img_name in os.listdir(img_path):
# 图片完整路径
img = f"{img_path}//{img_name}"
# 图片路径,标签[01]
self.dataset.append((img, label))
def __len__(self):
return len(self.dataset)
# 获取数据集中的一条数据
def __getitem__(self, index):
data = self.dataset[index]
img = cv2.imread(data[0], 0)
# 对图像进行展平,因为我们的图像是HWC,而我们的神经网络是 NV
img = img.reshape(-1)
# 归一化
img = img / 255
# 标签[01]
one_hot = np.zeros(2)
# 对应的位置赋值为 1
one_hot[int(data[1])] = 1
return np.float32(img), np.float32(one_hot)
5、进行训练和测试的实现
定义一个训练类,在初始化的时候会准备许多东西,之后就是训练和测试的函数实现
代码如下:
class Trainer:
# 初始化
def __init__(self):
# 创建一个Net_V1的神经网络实例
self.net = Net_V1()
# 根据是否有可用的GPU,选择在cuda或cpu上运行
self.device = "cuda" if torch.cuda.is_available() else "cpu"
# 将网络模型移动到所选的设备(GPU或CPU)
self.net.to(self.device)
# 创建用于训练的MNIST数据集实例,指定数据集路径和训练标志为True
self.train_dataset = MNIST_Dataset(r"D:\work\cat_dog\data", train=True)
# 创建用于训练数据的数据加载器,设置批量大小为100,随机打乱数据
self.train_loader = DataLoader(self.train_dataset, batch_size=100, shuffle=True)
# 创建用于测试的MNIST数据集实例,指定数据集路径和训练标志为False
self.test_dataset = MNIST_Dataset(r"D:\work\cat_dog\data", train=False)
# 创建用于测试数据的数据加载器,设置批量大小为100,随机打乱数据
self.test_loader = DataLoader(self.test_dataset, batch_size=100, shuffle=True)
# 优化器: Adam,优化神经网络模型的参数
self.opt = torch.optim.Adam(self.net.parameters())
# 训练
def train(self):
# 1轮次:20000张
for epoch in range(1, 20000):
sum_loss = 0.0
# 分批次batch_size训练
# tqdm.tqdm() 这个是在循环中显示进度的
# for i, (img, label) in enumerate(tqdm.tqdm(self.train_loader)):
for i, (img, label) in enumerate(self.train_loader):
# img.shape == 100, 784
# 开启训练模式
self.net.train() # dropout()
# GPU
img, label = img.to(self.device), label.to(self.device)
# 数据放入网络,前向计算,得到结果。
out = self.net(img)
# 标签与计算结果之间求损失
# 均方差
loss = torch.mean((label - out) ** 2)
# 损失,优化器,反向跟新
self.opt.zero_grad() # 清空梯度
loss.backward() # 梯度跟新
self.opt.step()
sum_loss = sum_loss + loss.item()
# 60000 100
# 计算平均损失
avg_loss = sum_loss / len(self.train_loader)
print(f"第{epoch}轮的损失是{avg_loss}")
# 保存结果:权重
torch.save(self.net.state_dict(), f"params//{epoch}.pt")
# 测试
def test(self):
# 10000 9800 98%
# 加载权重测试
# 循环自己保存的pt文件
for j in range(30, 130):
self.net.load_state_dict(torch.load(rf"params//{j}.pt"))
for epoch in range(1, 2):
sum_score = 0.0
for i, (img, label) in enumerate(tqdm.tqdm(self.test_loader)):
# 测试模式 不执行dropout
self.net.eval()
img, label = img.to(self.device), label.to(self.device)
# img.shape == [100, 784]
out = self.net(img)
# out.shape == [100, 10]
# out和label作比较,最大值的索引,比较eq,int(),sum()
x = torch.argmax(out, dim=1)
y = torch.argmax(label, dim=1)
# 得分
score = torch.sum(torch.eq(x, y).float())
sum_score = sum_score + score.item()
# 平均得分
avg_score = sum_score / len(self.test_loader)
print(f"第{j}轮的测试精度{avg_score}")
在主函数中进行对象实例化,并且调用我们的训练和测试
if __name__ == '__main__':
# 创建对象
trainer = Trainer()
# trainer.train()
trainer.test()
上面就是我们猫狗识别的基本流程:包含了全部的代码,需要的话,自己组合一下吧
感觉这个猫狗识别没什么太大的难度,也就没有详细的讲解其中的内容