自创数据集(img)

在当前目录下新建dataset,并在文件夹中,将图片分类在各自文件夹中,文件夹名为标签名

image-20230519212253680

import os
import random

# 选取60%作为训练数据集
train_radio = 0.6
text_radio = 1 - train_radio

root_data = r'dataset'

train_list, test_list = [], []
data_list = []

class_flag = -1
for a, b, c in os.walk(root_data):
print(a)
for i in range(len(c)):
data_list.append(os.path.join(a, c[i]))

for i in range(0, int(len(c) * train_radio)):
train_data = os.path.join(a, c[i]) + '\t' + str(class_flag) + '\n'
train_list.append(train_data)

for i in range(int(len(c) * train_radio), len(c)):
test_data = os.path.join(a, c[i]) + '\t' + str(class_flag) + '\n'
test_list.append(test_data)

class_flag += 1

print(train_list)
# 将列表中元素顺序随机打乱
random.shuffle(train_list)
random.shuffle(test_list)

with open('train.txt', 'w', encoding='utf-8') as f:
for train_img in train_list:
f.write(str(train_img))

with open('text.txt', 'w', encoding='utf-8') as f:
for test_img in test_list:
f.write(test_img)

会在当前目录下,生成train.txttest.txt,在会随机给不同的类分一个数字作为标签

image-20230519212528554

前面的图片路径为输入的x、后面的数字为标签y

转换为DataLoader

将自己的数据集转换为torch可接受的DataLoader,CreateDateloader.py

import torch
from PIL import Image

import torchvision.transforms as transforms
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

from torch.utils.data import Dataset

# 数据归一化与标准化

# 图像标准化
transform_BZ= transforms.Normalize(
mean=[0.5, 0.5, 0.5],# 取决于数据集
std=[0.5, 0.5, 0.5]
)


class LoadData(Dataset):
def __init__(self, txt_path, train_flag=True):
self.imgs_info = self.get_images(txt_path)
self.train_flag = train_flag

self.train_tf = transforms.Compose([
transforms.Resize(224),
transforms.RandomHorizontalFlip(),
transforms.RandomVerticalFlip(),
transforms.ToTensor(),
transform_BZ
])
self.val_tf = transforms.Compose([
transforms.Resize(224),
transforms.ToTensor(),
transform_BZ
])

def get_images(self, txt_path):
with open(txt_path, 'r', encoding='utf-8') as f:
imgs_info = f.readlines()
imgs_info = list(map(lambda x:x.strip().split('\t'), imgs_info))
return imgs_info

def padding_black(self, img):
w, h = img.size
scale = 224. / max(w, h)
img_fg = img.resize([int(x) for x in [w * scale, h * scale]])
size_fg = img_fg.size
size_bg = 224
img_bg = Image.new("RGB", (size_bg, size_bg))
img_bg.paste(img_fg, ((size_bg - size_fg[0]) // 2,
(size_bg - size_fg[1]) // 2))
img = img_bg
return img

def __getitem__(self, index):
img_path, label = self.imgs_info[index]
img = Image.open(img_path)
img = img.convert('RGB')
img = self.padding_black(img)
if self.train_flag:
img = self.train_tf(img)
else:
img = self.val_tf(img)
label = int(label)

return img, label

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


if __name__ == "__main__":
train_dataset = LoadData("train.txt", True)
print("数据个数:", len(train_dataset))
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
batch_size=10,
shuffle=True)
for image, label in train_loader:
print(image.shape)
print(image)
# img = transform_BZ(image)
# print(img)
print(label)

# test_dataset = Data_Loader("test.txt", False)
# print("数据个数:", len(test_dataset))
# test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
# batch_size=10,
# shuffle=True)
# for image, label in test_loader:
# print(image.shape)
# print(label)

运行的结果为数据个数,以及每张图片的张量

image-20230519230412452

开始定义模型

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda, Compose
import matplotlib.pyplot as plt
from CreateDataloader import LoadData


# 采用torchvision里面的datasets里面的FashionMNIST数据集,该数据集在第一次用时需要下载,
# 数据集分为训练集(用于模型训练)和测试集(验证模型性能)
# 下面是训练集
# training_data = datasets.FashionMNIST( # FashionMNIST
# root="data",
# train=True,
# download=True,
# transform=ToTensor(), # 数据预处理
# )
#
# # 下面是测试集,同样需要下载
# test_data = datasets.FashionMNIST(
# root="data",
# train=False,
# download=True,
# transform=ToTensor(),
# )

#


# 定义网络模型
class NeuralNetwork(nn.Module):
def __init__(self):
super(NeuralNetwork, self).__init__()
# 碾平,将数据碾平为一维
self.flatten = nn.Flatten()
# 定义linear_relu_stack,由以下众多层构成
self.linear_relu_stack = nn.Sequential(
# 全连接层
nn.Linear(3*224*224, 512),
# ReLU激活函数
nn.ReLU(),
# 全连接层
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 6),
nn.ReLU()
)
# x为传入数据
def forward(self, x):
# x先经过碾平变为1维
x = self.flatten(x)
# 随后x经过linear_relu_stack
logits = self.linear_relu_stack(x)
# 输出logits
return logits



# 定义训练函数,需要
def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
# 从数据加载器中读取batch(一次读取多少张,即批次数),X(图片数据),y(图片真实标签)。
for batch, (X, y) in enumerate(dataloader):
# 将数据存到显卡
X, y = X.cuda(), y.cuda()

# 得到预测的结果pred
pred = model(X)

# 计算预测的误差
# print(pred,y)
loss = loss_fn(pred, y)

# 反向传播,更新模型参数
optimizer.zero_grad()
loss.backward()
optimizer.step()

# 每训练100次,输出一次当前信息
if batch % 100 == 0:
loss, current = loss.item(), batch * len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")


def test(dataloader, model):
size = len(dataloader.dataset)
print("size = ",size)
# 将模型转为验证模式
model.eval()
# 初始化test_loss 和 correct, 用来统计每次的误差
test_loss, correct = 0, 0
# 测试时模型参数不用更新,所以no_gard()
# 非训练, 推理期用到
with torch.no_grad():
# 加载数据加载器,得到里面的X(图片数据)和y(真实标签)
for X, y in dataloader:
# 将数据转到GPU
X, y = X.cuda(), y.cuda()
# 将图片传入到模型当中就,得到预测的值pred
pred = model(X)
# 计算预测值pred和真实值y的差距
test_loss += loss_fn(pred, y).item()
# 统计预测正确的个数
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= size
correct /= size
print("correct = ",correct)
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")



if __name__=='__main__':
batch_size = 16

# # 给训练集和测试集分别创建一个数据集加载器
train_data = LoadData("train.txt", True)
valid_data = LoadData("test.txt", False)

# num_workers:cpu用来加载数据的子进程数 pin_memory:是否将数据保存在pin memory区,pin memory中的数据转到GPU会快一些
train_dataloader = DataLoader(dataset=train_data, num_workers=4, pin_memory=True, batch_size=batch_size, shuffle=True)
test_dataloader = DataLoader(dataset=valid_data, num_workers=4, pin_memory=True, batch_size=batch_size)

for X, y in test_dataloader:
print("Shape of X [N, C, H, W]: ", X.shape)
print("Shape of y: ", y.shape, y.dtype)
break


# 如果显卡可用,则用显卡进行训练
device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device))

# 调用刚定义的模型,将模型转到GPU(如果可用)
model = NeuralNetwork().to(device)

print(model)

# 定义损失函数,计算相差多少,交叉熵,
loss_fn = nn.CrossEntropyLoss()

# 定义优化器,用来训练时候优化模型参数,随机梯度下降法
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3) # 初始学习率


# 一共训练5次
epochs = 5
for t in range(epochs):
print(f"Epoch {t+1}\n-------------------------------")
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model)
print("Done!")

# 保存训练好的模型
# torch.save(model.state_dict(), "model.pth")
# print("Saved PyTorch Model State to model.pth")



# 读取训练好的模型,加载训练好的参数
model = NeuralNetwork()
model.load_state_dict(torch.load("model.pth"))


# # 定义所有类别
# classes = [
# "T-shirt/top",
# "Trouser",
# "Pullover",
# "Dress",
# "Coat",
# "Sandal",
# "Shirt",
# "Sneaker",
# "Bag",
# "Ankle boot",
# ]
#
# # 模型进入验证阶段
# model.eval()
#
# x, y = test_data[0][0], test_data[0][1]
# with torch.no_grad():
# pred = model(x)
# predicted, actual = classes[pred[0].argmax(0)], classes[y]
# print(f'Predicted: "{predicted}", Actual: "{actual}"')