Mnist数据集:包含60,000个用于训练的示例和10,000个用于测试的示例。这些数字已经过尺寸标准化并位于图像中心,图像是固定大小(28x28像素)。类别为数字0~9,共10类。
我们将Mnist数据集减少至只剩0、1的两类。
并使用lenet进行训练。
首先需要处理数据集:
需要自己新建文件夹,文件夹内包括图片(两个类别分成两个文件夹,如下)和图片对应的标签(下图中的txt,需要自己生成)
标签中包含:图片路径+类别(如下)
然后数据集部分就准备好了
代码修改:
原代码参考:https://www.bilibili.com/video/BV1vU4y1A7QJ/?spm_id_from=333.337.search-card.all.click
首先在代码根目录中新建.py文件,用于读取图片路径,代码如下:
from PIL import Image
from torch.utils.data import Dataset
import os
import time
import torch
from torch import nn
from torch.optim import lr_scheduler
from torchvision import datasets, transforms
import os
# from net import MyLeNet5
class MyDataset(Dataset):
def __init__(self, txt_path, transform = None, target_transform = None):
fh = open(txt_path, 'r')
imgs = []
for line in fh:
line = line.rstrip()
words = line.split()
imgs.append((words[0], words[1]))
self.imgs = imgs
self.transform = transform
self.target_transform = target_transform
def __getitem__(self, index):
fn, label = self.imgs[index]
#img = Image.open(fn).convert('RGB')
img = Image.open(fn)
if self.transform is not None:
img = self.transform(img)
return img, label
def __len__(self):
return len(self.imgs)
pipline_train = transforms.Compose([
#随机旋转图片
transforms.RandomHorizontalFlip(),
#将图片尺寸resize到32x32
transforms.Resize((32,32)),
#将图片转化为Tensor格式
transforms.ToTensor(),
#正则化(当模型出现过拟合的情况时,用来降低模型的复杂度)
transforms.Normalize((0.1307,),(0.3081,))
])
pipline_test = transforms.Compose([
#将图片尺寸resize到32x32
transforms.Resize((32,32)),
transforms.ToTensor(),
transforms.Normalize((0.1307,),(0.3081,))
])
train.py中引用,xjj就是我在根目录中新建py,xjj.py
train.py中将读取数据集部分改为:
train_data = MyDataset('./data/LEDNUM/train.txt', transform=data_transform)
test_data = MyDataset('./data/LEDNUM/test.txt', transform=data_transform)
#train_data 和test_data包含多有的训练与测试数据,调用DataLoader批量加载
trainloader = torch.utils.data.DataLoader(dataset=train_data, batch_size=8, shuffle=True)
testloader = torch.utils.data.DataLoader(dataset=test_data, batch_size=4, shuffle=False)
train.py中修改定义训练函数:
def train(dataloader, model, loss_fn, optimizer):
loss, current, n = 0.0, 0.0, 0
#numerate()会返回两个值, 一个是索引, 一个是数据,numerate()需要两个参数: 第一个参数是可迭代的对象,第二个参数是起始位置, 数据类型为int
for batch, (X,y) in enumerate(dataloader):#enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
#前向转播
# X, y = X.to(device), y.to(device)
X, y = X, y
output = model(X)
##########
y_ = y
label_y = []
for _ in y_:
item = int(_)
label_y.append(item)
# y = list(y)
y = torch.tensor(label_y)
#print(type(y))
###############
cur_loss = loss_fn(output, y)
_, pred = torch.max(output, axis=1)#通过torch.max输出每一行的最大概率
cur_acc = torch.sum(y == pred)/output.shape[0]#16个批次即16张照片,通过y与预测值pred相比较,判断预测是否准确,如果准确返回1,不准确返回0,最后所有的加起来判断一批次的精确度,最后通过for判断一轮的精确度,得动精确度权重
#反向传播
optimizer.zero_grad()#优化器梯度清理
cur_loss.backward()
optimizer.step()#梯度更新
loss += cur_loss.item()#把这一批次的损失值累加的一起
current += cur_acc.item()#把所有的精度累加的一起
n = n+1
print("train_loss" + str(loss/n))#每一轮平均损失
print("train_acc" + str(current/n))#每一轮平均精确度
这步增加了更改数据集格式,将图片矩阵改为张量
train.py中修改定义验证函数:
def val(dataloader, model, loss_fn):
#model.eval()是保证BN(Batch Normalization分批归一化)用全部数据的均值和方差;
model.eval()#改为验证模式,eval() 函数用来执行一个字符串表达式,并返回表达式的值。model.eval() 作用等同于 self.train(False)简而言之,就是评估模式
loss, current, n = 0.0, 0.0, 0
with torch.no_grad():#在模型不参与更新的情况下进行验证
for batch, (X, y) in enumerate(dataloader):
##########
y_ = y
label_y = []
for _ in y_:
item = int(_)
label_y.append(item)
# y = list(y)
y = torch.tensor(label_y)
# print(type(y))
###############
# 前向转播
# X, y = X.to(device), y.to(device)
output = model(X)
cur_loss = loss_fn(output, y)
_, pred = torch.max(output, axis=1)
cur_acc = torch.sum(y == pred) / output.shape[0]
loss += cur_loss.item()
current += cur_acc.item()
n = n + 1
print("val_loss" + str(loss / n))
print("val_acc" + str(current / n))
return current/n#返回精确度,精确度越高模型越好
net.py中修改类别和类别数
然后就可以训练了,结果如下: