一、Fashion-MNIST数据集
Fashion-MNIST包含了各种不同类型的时尚物品的灰度图像,每张图像尺寸为28X28,该数据集共包含70000张图片,其中训练集共60000张,测试集10000张。数据集一共有十个类别,分别为T-shirt(T恤)、Trouser、Pullover、Dress、Coat、Sandal、Shirt、Sneaker、Bag、Ankle boot。
二、LeNet
LeNet,它是最早发布的卷积神经网络之一,因其在计算机视觉任务中的高效性能而受到广泛关注。 这个模型是由AT&T贝尔实验室的研究员Yann LeCun在1989年提出的(并以其命名),目的是识别图像 (LeCun et al., 1998)中的手写数字。
模型结构图:
每个卷积块中的基本单元是一个卷积层、一个sigmoid激活函数和平均汇聚层。每个卷积层使用卷积核和一个sigmoid激活函数。这些层将输入映射到多个二维特征输出,通常同时增加通道的数量。第一卷积层有6个输出通道,而第二个卷积层有16个输出通道。每个
池操作(步幅2)通过空间下采样将维数减少4倍。卷积的输出形状由批量大小、通道数、高度、宽度决定。
为了将卷积块的输出传递给全连接层,需要在小批量中展平每个样本。即将四维输入转换成全连接层所期望的二维输入。这里的二维表示的第一个维度索引小批量中的样本,第二个维度给出每个样本的平面向量表示。LeNet的稠密块有三个全连接层,分别有120、84和10个输出。
LeNet简化版模型:
三、训练和测试模型
import torch
import torchvision.datasets
from torch import nn
from torch.utils.data import DataLoader
from matplotlib import pyplot as plt
#准备数据集
train_data=torchvision.datasets.FashionMNIST('./data',train=True,transform=torchvision.transforms.ToTensor(),download=True)
test_data=torchvision.datasets.FashionMNIST('./data',train=False,transform=torchvision.transforms.ToTensor(),download=True)
train_data_size=len(train_data)
test_data_size=len(test_data)
print(train_data_size)
print(test_data_size)
#使用DataLoader加载数据 组合了数据集(dataset) + 采样器(sampler)
train_dataloader=DataLoader(train_data,batch_size=64,drop_last=True)
test_dataloader=DataLoader(test_data,batch_size=64,drop_last=True)
#定义模型
class LeNet(nn.Module):
def __init__(self):
super().__init__()
self.models=nn.Sequential(
nn.Conv2d(1,6,5,padding=2),nn.Sigmoid(),
nn.MaxPool2d(2,stride=2),
nn.Conv2d(6,16,5),nn.Sigmoid(),
nn.MaxPool2d(2,stride=2),
nn.Flatten(),
nn.Linear(16*5*5,120),
nn.Sigmoid(),
nn.Linear(120,84),
nn.Sigmoid(),
nn.Linear(84,10)
)
def forward(self,x):
x=self.models(x)
return x
net=LeNet()
#定义损失函数和优化器
loss_fn=nn.CrossEntropyLoss()
optimizer=torch.optim.SGD(net.parameters(),lr=0.9)
#设置训练参数
epoch=10
total_train_step=0
train_loss_list=[]
total_accuracy_list=[]
total_loss_list=[]
x=[]
#训练模型
for i in range(epoch):
print(f'第{i+1}轮训练开始')
# 设置成训练模式
train_loss=0
net.train()
for data in train_dataloader:
imgs,targets=data
outputs=net(imgs)
#计算损失
loss=loss_fn(outputs,targets)
# train_loss += loss.item()
optimizer.zero_grad()
#计算梯度
loss.backward()
#更新参数
optimizer.step()
total_train_step+=1
# if total_train_step%100==0:
# print(f'训练次数{total_train_step},Loss:{loss.item()}')
#测试模型
total_test_loss = 0
total_accuracy=0
net.eval()
with torch.no_grad():
for data in test_dataloader:
imgs,targets=data
outputs=net(imgs)
loss=loss_fn(outputs,targets)
total_test_loss+=loss.item()
accuracy=(outputs.argmax(1)==targets).sum()
total_accuracy+=accuracy
print(f'整体上的测试损失:{total_test_loss/test_data_size}')
print(f'整体上的测试精度:{total_accuracy/test_data_size}')
total_loss_list.append(total_test_loss/test_data_size)
total_accuracy_list.append(total_accuracy/test_data_size)
#保存模型
torch.save(net,f'model{i}.pth')
#可视化
x=range(1,11)
plt.xticks(range(0,12,2))
plt.plot(x,total_accuracy_list,label="test acc")
plt.plot(x,total_loss_list,label="test loss")
plt.xlabel("epoch")
plt.legend()
plt.show()
四、预测
import os
import torch
import torchvision.transforms
from PIL import Image
from torch import nn
from matplotlib import pyplot as plt
#1.定义模型
class LeNet(nn.Module):
def __init__(self):
super().__init__()
self.models=nn.Sequential(
nn.Conv2d(1,6,5,padding=2),nn.Sigmoid(),
nn.MaxPool2d(2,stride=2),
nn.Conv2d(6,16,5),nn.Sigmoid(),
nn.MaxPool2d(2,stride=2),
nn.Flatten(),
nn.Linear(16*5*5,120),
nn.Sigmoid(),
nn.Linear(120,84),
nn.Sigmoid(),
nn.Linear(84,10)
)
def forward(self,x):
x=self.models(x)
return x
#2.加载与训练好的模型
model=torch.load("model9.pth")
#3.定义类别标签
classes=['T-shirt','Trouser','Pullover','Dress','Coat','Sandal','Shirt','Sneaker','Bag','Ankle boot']
#4.获取图片的全路径
img_root="images"
#获取图片文件夹下所有图片的名称
file_name=os.listdir(img_root)
file_path=[]
for name in file_name:
file_path.append(os.path.join(img_root,name))
#5.预测
for path in file_path:
#打开图片
imagePIL=Image.open(path)
#三通道图像转换成一通道,黑白图形
image_gray=imagePIL.convert("L")
#将PIL图片转换成tensor格式并转换成转换成模型输入图片的大小 28X28
transform=torchvision.transforms.Compose([torchvision.transforms.Resize((28,28)),
torchvision.transforms.ToTensor()])
imageTensor=transform(image_gray)
#调整图片的维度,与模型相对应
imageTensor=torch.reshape(imageTensor,(1,1,28,28))
#设置为预测模式
model.eval()
with torch.no_grad():
output=model(imageTensor)
#获取预测类别
predict_class=classes[output.argmax(1)]
#获取类别的概率
predict_probability =torch.softmax(output, dim=1).numpy()[0][output.argmax(1)]
print(predict_class)
# 绘制原始图片和显示预测的值
plt.imshow(image_gray)
plt.title("predict:{}".format(predict_class))
plt.text(5, 45, "probability {}:{}".format(predict_class, predict_probability), bbox=dict(fc='red'))
plt.show()