Cifar10 数据集的读取、加载、训练

本文主要分为4个模块,分别是

1 readCifar10
首先进行数据集的读取工作,建立对应标签并将对应图像放入标签文件夹内。

2 loadCifar10
接下来对数据集进行加载,构建DataLoader类(会使用到我们的MyDataset类)MyDataset类会初始化加载器以及转换方式

3 VggNet
自定义VggNet 串联的一个神经网络 进行初始化以及向前传播函数

4 train
函数 向前传播 计算损失 参数置零 反向传播 参数更新

read


import pickle
import glob
import cv2
import numpy as np
import os


# 读取数据集合步骤 利用 glob 的glob 函数得到 存储图片的几个文件夹 train_list
# 对文件夹进行反序列化 pickle.load() 函数  得到文件本身的数据
# print 这个文件(字典类型)里面的key值()
# dict_keys([b'batch_label', b'labels', b'data', b'filenames'])
# 然后 对某一个维度进行遍历  利用enumerate函数  得到 每一个数据项的idx
# 进而得到label以及data
# 并将data的 形状(reshape) 以及 通道排序(transpose)转化为合适后续操作的形式

# save_path = "D:\\PostgraduateStudy\\learn_pytorch\\Dataset\\cifar-10-batches-py\\train"
save_path = "D:\\PostgraduateStudy\\learn_pytorch\\Dataset\\cifar-10-batches-py\\test"
def unpickle(file):
    with open(file, "rb") as fo:
        dict = pickle.load(fo, encoding="bytes")
    return dict

label_name =["airplane",
             "automobile",
             "bird",
             "cat",
             "deer",
             "dog",
             "frog",
             "horse",
             "ship",
             "truck"]

train_list = glob.glob("D:\\PostgraduateStudy\\learn_pytorch"
                       "\\Dataset\\cifar-10-batches-py\\test_batch")

print(train_list)

for l in train_list:
    l_dict = unpickle(l)
    print(l_dict.keys())
    #dict_keys([b'batch_label', b'labels', b'data', b'filenames'])
    for im_idx, im_data in enumerate(l_dict[b"data"]):
        # 遍历字典中 data 这个维度
        # enumerate()函数表示将列表、字符串等可遍历的数据对象组成一个索引序列
        # print(im_idx)
        # print(im_data)
        im_name = l_dict[b"filenames"][im_idx]
        im_label = l_dict[b"labels"][im_idx]
        print(im_name, im_label, im_data)

        im_lable_name = label_name[im_label]#Cifar10 里面的label 是0 1 2 3 4 故转化为 dog ship
        im_data = np.reshape(im_data, [3, 32, 32])
        im_data = np.transpose(im_data, [1, 2, 0])# 对空间矩阵的进行转置
        # cv2.imshow("data",im_data)
        # cv2.waitKey(0)
        if not os.path.exists("{}/{}".format(save_path, im_lable_name)):
            os.mkdir("{}/{}".format(save_path, im_lable_name))
        cv2.imwrite("{}/{}/{}".format(save_path, im_lable_name,
                                      im_name.decode("utf-8")) ,im_data)

load

from torchvision import transforms
from torch.utils.data import DataLoader, Dataset
import os
import glob
from PIL import Image
import numpy as np
# read 读取到数据之后 对自定义数据进行加载
#列表类型

label_name =["airplane",
             "automobile",
             "bird",
             "cat",
             "deer",
             "dog",
             "frog",
             "horse",
             "ship",
             "truck"]

#字典类型
label_dict = {}

for idx, name in enumerate(label_name):
    #一般用于for循环。
    # enumerate()在遍历中可以获得索引和元素值。
    label_dict[name] = idx

def default_loader(path):
    return Image.open(path).convert("RGB")

train_transform = transforms.Compose([
    # 组合进行图片转换的几个方法
    transforms.RandomResizedCrop(28),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor()
])

test_transform = transforms.Compose([
    # 组合进行图片转换的几个方法
    transforms.RandomResizedCrop((28, 28)),
    transforms.ToTensor()
])

class MyDataset(Dataset):
    def __init__(self, im_list,
                 transforms=None,
                 loader = default_loader):
        #传入要进行加载的文件, 对图片进行增强的函数, 加载器
        super(MyDataset, self).__init__()
        imgs = []
        for item in im_list:
        #"D:\PostgraduateStudy\learn_pytorch\Dataset\cifar-10-batches-py\train
        # \airplane\aeroplane_s_000004.png"
            im_label_name = item.split("\\")[-2]
            #print(im_label_name)
            imgs.append([item, label_dict[im_label_name]])
            # 给列表中 增加 元素的时候元素有两个信息的时候 利用列表套列表的方式
        self.imgs = imgs
        self.transforms = transforms
        self.loader = loader

    def __getitem__(self, index):
        #定义对数据的读取和对数据的增强 返回图片的数据以及label
        im_path, im_label = self.imgs[index]
        im_data = self.loader(im_path)
        if self.transforms is not None:
            im_data = self.transforms(im_data)
        return im_data, im_label

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

im_train_list = glob.glob("D:\\PostgraduateStudy\\learn_pytorch\\Dataset\\cifar-10-batches-py\\train\\*\\*.png")
im_test_list = glob.glob("D:\\PostgraduateStudy\\learn_pytorch\\Dataset\\cifar-10-batches-py\\test\\*\\*.png")

train_dataset = MyDataset(im_train_list, transforms = train_transform)
test_dataset = MyDataset(im_train_list, transforms = test_transform)
#测试集不需要增强

train_data_loader = DataLoader(dataset=train_dataset,
                               batch_size=128,
                               shuffle=True,
                               num_workers=2)
#batchsize 每一批次输入的个数
test_data_loader = DataLoader(dataset=test_dataset,
                              batch_size=128,
                              shuffle=False,
                              num_workers=2)
print("num of train", len(train_dataset))
print("num of test", len(test_dataset))

VggNet

import torch
import torch.nn as nn
import torch.nn.functional as F
#对数据进行加载之后 进行神经网络的学习
class VGGbase(nn.Module):
    def __init__(self):
        super(VGGbase, self).__init__()
        #调用父类的初始化方法
        # 3 * 28 * 28 (crop --》 32, 28)
        self.conv1 = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, stride=1,padding=1),
            # 在这里 卷积核是3*3   卷积完成后输出的特征矩阵加一个
            # padding =1 的边框(相当于 给特征矩阵宽和高都加2)
            nn.BatchNorm2d(64),
            nn.ReLU() # 非线性激活函数
        )
        self.max_pooling1 = nn.MaxPool2d(kernel_size=2, stride=2)

        # 14 * 14
        self.conv2_1 = nn.Sequential(
            nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
            # 在这里 卷积核是3*3   卷积完成后输出的特征矩阵加一个
            # padding =1 的边框(相当于 给特征矩阵宽和高都加2)
            nn.BatchNorm2d(128),
            nn.ReLU()
        )
        self.conv2_2 = nn.Sequential(
            nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1),
            # 在这里 卷积核是3*3   卷积完成后输出的特征矩阵加一个
            # padding =1 的边框(相当于 给特征矩阵宽和高都加2)
            nn.BatchNorm2d(128),
            nn.ReLU()
        )
        self.max_pooling2 = nn.MaxPool2d(kernel_size=2, stride=2)

        # 7 *7
        self.conv3_1 = nn.Sequential(
            nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
            # 在这里 卷积核是3*3   卷积完成后输出的特征矩阵加一个
            # padding =1 的边框(相当于 给特征矩阵宽和高都加2)
            nn.BatchNorm2d(256),
            nn.ReLU()
        )
        self.conv3_2 = nn.Sequential(
            nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
            # 在这里 卷积核是3*3   卷积完成后输出的特征矩阵加一个
            # padding =1 的边框(相当于 给特征矩阵宽和高都加2)
            nn.BatchNorm2d(256),
            nn.ReLU()
        )
        self.max_pooling3 = nn.MaxPool2d(kernel_size=2, stride=2, padding=1)

         # 4*4
        self.conv4_1 = nn.Sequential(
            nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),
            # 在这里 卷积核是3*3   卷积完成后输出的特征矩阵加一个
            # padding =1 的边框(相当于 给特征矩阵宽和高都加2)
            nn.BatchNorm2d(512),
            nn.ReLU()
        )
        self.conv4_2 = nn.Sequential(
            nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
            # 在这里 卷积核是3*3   卷积完成后输出的特征矩阵加一个
            # padding =1 的边框(相当于 给特征矩阵宽和高都加2)
            nn.BatchNorm2d(512),
            nn.ReLU()
        )
        self.max_pooling4 = nn.MaxPool2d(kernel_size=2, stride=2)
        # 2*2

        # 想要对其进行全连接故变成2维的tensor
        # batchsize * 512 * 2 * 2 -----》 batchsize * (512 * 4)
        self.fc = nn.Linear(512*2*2, 10)

    def forward(self, x):
        #print("你执行到了我")
        batchsize = x.size(0)
        out = self.conv1(x)
        out = self.max_pooling1(out)
        out = self.conv2_1(out)
        out = self.conv2_2(out)
        out = self.max_pooling2(out)
        out = self.conv3_1(out)
        out = self.conv3_2(out)
        out = self.max_pooling3(out)
        out = self.conv4_1(out)
        out = self.conv4_2(out)
        out = self.max_pooling4(out)
        out = out.view(batchsize, -1)
        # batchsize * c * h * w --> batchsize * c * n
        out = self.fc(out)# batchsize * 10

        out = F.log_softmax(out, dim=1)
        # 对每一行的所有元素进行softMax计算,使得每一行元素和为1
        # 对得到的结果进行log运算
        return out

def VGGNet():
    return VGGbase()

train

import os
import torch
import torch.nn as nn
import torchvision
import tensorboardX
from cpVggNet import VGGbase
from cpload_Cifar10 import test_data_loader, train_data_loader

if __name__ == '__main__':
    # 向前传播  计算损失  参数归0  反向传播  参数更新
    # 定义环境
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    epoch_num = 100  # 对样本一共遍历200次
    lr = 0.01
    net = VGGbase().to(device)
    batch_size = 128
    # loss 交叉熵
    loss_func = nn.CrossEntropyLoss()
    step_n = 0
    # optimizer
    optimizer = torch.optim.Adam(net.parameters(), lr=lr)
    # optimizer = torch.optim.SGD(net.parameters(), lr = lr,
    #                             momentum=0.9, weight_decay=5e-4)

    scheduler = torch.optim.lr_scheduler.StepLR(optimizer,
                                                step_size=1,
                                                gamma=0.9)
    if not os.path.exists("log"):
        os.mkdir("log")
    writer = tensorboardX.SummaryWriter("log")
    # 学习率呈现递减的趋势
    for epoch in range(epoch_num):
        #将数据集遍历epoch_num次
        net.train()
        for i, data in enumerate(train_data_loader):
            #dataloader 里面的batchiszie 为128  num of train 50000
            #因此需要5000/128次才能够完成一次 train_data的遍历
            inputs, labels = data
            inputs, labels = inputs.to(device), labels.to(device)
            #print(inputs)
            outputs = net(inputs)
            # 这个语句的后面是 net = VGGbase().to(device)
            # def VGGNet():
            #     return VGGbase()
            # 会执行到构造函数 以及 forward 函数
            # forward 函数里面会返回 out
            #print(type(outputs))
            #print(outputs)
            loss = loss_func(outputs, labels)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            #打印每一个minibatch 的loss
            _,pred = torch.max(outputs.data, dim=1)
            #torch.max
            #返回输入张量给定维度上每行的最大值,并同时返回每个最大值的位置索引
            #print("_:",_,"pred:",pred)
            # 概率最大的位置 就是最后预测的值 dim = 1 是行中最大的元素
            correct = pred.eq(labels.data).cpu().sum()
            #print("train epoch", epoch, "step:", i, "loss is:", loss.item(),
            #      "mini-batch correct is:", 100.0 * correct / batch_size)
            # #print(net.state_dict) 可以查看网络之中的各个卷积层以及池化层的参数信息
            #print("train lr is", optimizer.state_dict()["param_groups"][0]["lr"])

            writer.add_scalar("train loss",loss.item(), global_step=step_n)
            writer.add_scalar("train correct",
                              100.0 * correct / batch_size, global_step=step_n)

            im = torchvision.utils.make_grid(inputs)
            writer.add_image("train_im", im, global_step=step_n)

            step_n +=1

        if not os.path.exists("models"):
            os.mkdir("models")
        torch.save(net.state_dict(),"models/{}.pth".format(epoch+1))
        # state_dict作为python的字典对象将每一层的参数映射成tensor张量
        scheduler.step()#对学习率进行更新

        #对数据进行测试
        sum_loss = 0
        sum_correct = 0
        for i, data in enumerate(test_data_loader):
            net.eval()
            #标志着当前是在做测试
            inputs, labels = data
            inputs, labels = inputs.to(device), labels.to(device)
            # print(inputs)
            outputs = net(inputs)
            loss = loss_func(outputs, labels)
            optimizer.zero_grad()
            _, pred = torch.max(outputs.data, dim=1)
            correct = pred.eq(labels.data).cpu().sum()

            sum_correct += correct.item()
            sum_loss += loss.item()
            writer.add_scalar("test loss", loss.item(), global_step=step_n)
            writer.add_scalar("test correct",
                              100.0 * correct / batch_size, global_step=step_n)
            im = torchvision.utils.make_grid(inputs)
            writer.add_image("test_im", im, global_step=step_n)

            step_n +=1
        test_loss = sum_loss / len(test_data_loader)
        test_correct = sum_correct * 100.0 / len(test_data_loader) / batch_size
        print("test epoch", epoch,  "loss is:", test_loss,
                  "mini-batch correct is:", test_correct)

    writer.close()

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值