一.撸前有话说
文件目录形式是较为常见的一种数据集格式,例如最为常见的猫狗数据集,还有花朵、交通工具。
其结构如juejin.cn/post/707813… 中2.2所示,具体可如下:\
类推:每个文件夹下都是同种类别的图像
二.动手开始撸
如果使用文件目录形式进行数据的读取的话就较为轻松了,我们使用torchvision包中的ImageFolder类针对文件目录形式快速创建dataset。
基本流程:
2.1 输入图像的路径(训练测试)
2.2 torchvision.datasets.ImageFolder解决战斗
2.3 对ImageFolder读取的dataset进行DataLoader
代码片段:
""" 使用torchvision包中的ImageFolder类针对文件目录形式快速创建dataset """ import torchvision.datasets from torch.utils.data import DataLoader # 输入训练和测试集的路径 train_root = '' # 图像的路径 test_root = '' # 图像的路径 # 将文件夹的内容载入dataset train_dataset = torchvision.datasets.ImageFolder(root=train_root) test_dataset = torchvision.datasets.ImageFolder(root=test_root) # DataLoader 读取数据 train_loader = DataLoader(dataset=train_dataset, # 输入自己要加载的数据set batch_size=3, # 一个批量的大小 shuffle=True, # 是否打乱顺序 num_workers=4, # 是否使用多进程,0代表不使用 pin_memory=True, # 是否将数据保存在pin_memory区, pin_memory数据转移到Gpu中会快一些 drop_last=True) # 当为Ture时,dataset中的数据个数不是batch_size整数倍时,将多余出不足一个batch的数据丢弃 test_loader = DataLoader(dataset=test_dataset, # 输入自己要加载的数据set batch_size=3, # 一个批量的大小 shuffle=True, # 是否打乱顺序 num_workers=4, # 是否使用多进程,0代表不使用 pin_memory=True, # 是否将数据保存在pin_memory区, pin_memory数据转移到Gpu中会快一些 drop_last=True) # 当为Ture时,dataset中的数据个数不是batch_size整数倍时,将多余出不足一个batch的数据丢弃
接下来就可以参考juejin.cn/post/707813… 或 juejin.cn/post/707783… 把训练部分摘过来稍加改动即可进行训练了\
三.撸完:demo:
""" 使用torchvision包中的ImageFolder类针对文件目录形式快速创建dataset """ import torchvision.datasets import time import numpy as np import torch import torch.nn as nn import torch.backends.cudnn as cudnn from PIL import Image from torch import optim from torch.autograd import Variable from torch.utils.data import Dataset, DataLoader class Net(nn.Module): def __init__(self, in_c=1200, out_c=10): super(Net, self).__init__() # 定义全连接层 self.fc1 = nn.Linear(in_c, 512) # 定义激活层 self.act1 = nn.ReLU(inplace=True) self.fc2 = nn.Linear(512, 256) self.act2 = nn.ReLU(inplace=True) self.fc3 = nn.Linear(256, 128) self.act3 = nn.ReLU(inplace=True) self.fc4 = nn.Linear(128, out_c) def forward(self, x): x = self.act1(self.fc1(x)) x = self.act2(self.fc2(x)) x = self.act3(self.fc3(x)) x = self.fc4(x) return x ## class MnistDataset(Dataset): def __init__(self, image_path, image_label, transform=None): super(MnistDataset, self).__init__() self.image_path = image_path # 初始化图像路径列表 self.image_label = image_label # 初始化图像标签列表 self.transform = transform # 初始化数据增强方法 def __getitem__(self, index): """ 获取对应index的图像,并视情况进行数据增强 """ image = Image.open(self.image_path[index]) image = np.asarray(image) label = float(self.image_label[index]) if self.transform is not None: image = self.transform(image) return image, torch.tensor(label) def __len__(self): return len(self.image_path) if __name__ == '__main__': # 输入训练和测试集的路径 train_root = './data - 副本/train/' test_root = './data - 副本/test/' # 将文件夹的内容载入dataset train_dataset = torchvision.datasets.ImageFolder(root=train_root,transform=torchvision.transforms.ToTensor()) test_dataset = torchvision.datasets.ImageFolder(root=test_root,transform=torchvision.transforms.ToTensor()) # DataLoader 读取数据 train_data = DataLoader(dataset=train_dataset, # 输入自己要加载的数据set batch_size=5, # 一个批量的大小 shuffle=True, # 是否打乱顺序 num_workers=4, # 是否使用多进程,0代表不使用 pin_memory=True, # 是否将数据保存在pin_memory区, pin_memory数据转移到Gpu中会快一些 drop_last=True) # 当为Ture时,dataset中的数据个数不是batch_size整数倍时,将多余出不足一个batch的数据丢弃 test_data = DataLoader(dataset=test_dataset, # 输入自己要加载的数据set batch_size=5, # 一个批量的大小 shuffle=True, # 是否打乱顺序 num_workers=4, # 是否使用多进程,0代表不使用 pin_memory=True, # 是否将数据保存在pin_memory区, pin_memory数据转移到Gpu中会快一些 drop_last=True) # 当为Ture时,dataset中的数据个数不是batch_size整数倍时,将多余出不足一个batch的数据丢弃 t1 = time.time() # 搭建网络 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') net = Net() cudnn.benchmark = True net = net.to(device) # 定义损失函数 -- 交叉熵 criterion = torch.nn.CrossEntropyLoss().to(device) # 定义优化器 -- 随机梯度下降 optimizer = optim.SGD(net.parameters(), lr=0.01, weight_decay=0.00005) # 开始训练 losses = [] # 记录训练损失 acces = [] # 记录训练精度 eval_losses = [] # 记录测试损失 eval_acces = [] # 记录测试精度 nums_epoch = 20 # 训练次数 for epoch in range(nums_epoch): train_loss = 0 # 设置训练损失的初始值 train_acc = 0 # 设置训练精度的初始值 net.train() for batch, (img, label) in enumerate(train_data): img = img.reshape(img.size(0), -1) img = Variable(img) img = img.to(device) label = Variable(label) label = label.to(device) # 向前传播 out = net(img) loss = criterion(out, label.long()) # 反向传播 optimizer.zero_grad() loss.backward() optimizer.step() # 记录误差 train_loss += loss.item() # 计算分类正确率 _, pred = out.max(1) num_correct = (pred == label.long()).sum().item() acc = num_correct / img.shape[0] if (batch + 1) % 200 == 0: print( '[INFO] Epoch-{}-Batch-{}: Train: Loss-{:.4f},Accuracy-{:.4f}'.format(epoch + 1, batch + 1, loss.item(), acc)) train_acc += acc losses.append(train_acc / len(train_data)) acces.append(train_acc / len(train_data)) eval_loss = 0 eval_acc = 0 # 测试集不训练 for img, label in test_data: img = img.reshape(img.size(0), -1) img = Variable(img) img = img.to(device) label = Variable(label) label = label.to(device) out = net(img) loss = criterion(out, label.long()) eval_loss += loss.item() _, pred = out.max(1) num_correct = (pred == label.long()).sum().item() acc = num_correct / img.shape[0] eval_acc += acc eval_losses.append(eval_loss / len(test_data)) eval_acces.append(eval_acc / len(test_data)) # 打印参数 set_epoch = epoch + 1 set_lossTrain = train_loss / len(train_data) set_AccTrain = train_acc / len(train_data) set_lossEval = eval_loss / len(test_data) set_AccEval = eval_acc / len(test_data) print('[INFO] Epoch-{}: Train: Loss-{:.4f},Accuracy-{:.4f} |Test:Loss-{:.4f}, Accuracy-{:.4f}'.format(set_epoch, set_lossTrain, set_AccTrain, set_lossEval, set_AccEval)) torch.save(net.state_dict(), 'saveNet.pth') t2 = time.time() t = t2 - t1 print(t)