下载 CIFAR-10数据集:

官网:https://www.cs.toronto.edu/~kriz/cifar.html

Pytorch关于CIFAR-10测试-LMLPHP

  CIFAR-10的网络结构:

Pytorch关于CIFAR-10测试-LMLPHP

import torch
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential



#定义网络结构
class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.model1 = Sequential(
            Conv2d(3,32,5,stride=1,padding=2),
            MaxPool2d(2),
            Conv2d(32,32,5,padding=2),
            MaxPool2d(2),
            Conv2d(32,64,5,padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(64*4*4,64),
            Linear(64,10)
        )

    def forward(self,x):
        x = self.model1(x)
        return x

model = Model()
print(model)

input = torch.ones((64,3,32,32))
print(input.shape)
output = model(input)
print(output.shape)

早起模型和现在比较:和上面的是等价的

import torch
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.tensorboard import SummaryWriter

#步长的计算方法:
# 例:一个尺寸 a*a 的特征图,经过 b*b 的卷积层,步幅(stride)=c,填充(padding)=d,请计算出输出的特征图尺寸?
# 特征图的尺寸=(a-b+2d)/c+1
#定义模型结构
class Model(nn.Module):
    def __init__(self) -> None:
        super().__init__()  # 初始化父类属性
        # self.conv1 = Conv2d(in_channels=3, out_channels=32,
        #                     kernel_size=5, padding=2)
        # self.maxpool1 = MaxPool2d(kernel_size=2)
        # self.conv2 = Conv2d(in_channels=32,out_channels=32,
        #                     kernel_size=5, padding=2)
        # self.maxpool2 = MaxPool2d(kernel_size=2)
        # self.conv3 = Conv2d(in_channels=32, out_channels=64,
        #                     kernel_size=5, padding=2)
        # self.maxpool3 = MaxPool2d(kernel_size=2)
        # self.flatten = Flatten()  # 展平为1维向量,torch.reshape()一样效果
        # # 若是想检验1024是否正确,可以先写前面的层,看样例的输出大小,即可得到1024
        # self.linear1 = Linear(in_features=1024, out_features=64)
        # self.linear2 = Linear(in_features=64, out_features=10)

        # sequential可以替代前面备注掉的代码段
        self.model1 = Sequential(
            Conv2d(3, 32, 5, stride=1, padding=2), #输入3张图片,也就是三通道,生成32张,卷积核5*5,不常是1,padding是2
            MaxPool2d(2), #对输出进行池化2*2
            Conv2d(32, 32, 5, padding=2), #输入32张,输出32张,卷积核是5*5,padding是2
            MaxPool2d(2), #池化2*2
            Conv2d(32, 64, 5, padding=2), #输入是32,输出是64,卷积核是5*5,padding是5*5
            MaxPool2d(2), #池化2*2
            Flatten(), #扁平化
            Linear(1024, 64), #全连接输入1024,输出64
            Linear(64, 10) #输入64,输出10(表示10个分类)
        )

    def forward(self, x):
        # x = self.conv1(x)
        # x = self.maxpool1(x)
        # x = self.conv2(x)
        # x = self.maxpool2(x)
        # x = self.conv3(x)
        # x = self.maxpool3(x)
        # x = self.flatten(x)
        # x = self.linear1(x)
        # x = self.linear2(x)

        #代替以上代码段
        x = self.model1(x) #将x传入模型,进行前向网络
        return x


model = Model()  # 创建一个实例
print(model)  # 打印模型结构

# 测试模型样例(也可以测试各层的输出是否正确)
input = torch.ones((64, 3, 32, 32))  #输入64张图片,3通道,32*32
print(input.shape)  # torch.Size([64, 3, 32, 32])
output = model(input) #模型的输出
print(output.shape)  # torch.Size([64, 10]),batch_size=64,10个参数

writer = SummaryWriter("./logs_seq")  # 创建一个实例
writer.add_graph(model, input)  # 显示模型结构
writer.close()

# tensorboard命令:tensorboard --logdir=logs_seq --port=6007



'''
torch.nn.functional.conv2d 和 torch.nn.Conv2d的区别?
nn.Conv2d是一个类,而F.conv2d()是一个函数,而nn.Conv2d的forward()函数实现是用F.conv2d()实现的(在Module类里的__call__实现了forward()函数的调用,所以当实例化nn.Conv2d类时,forward()函数也被执行了,详细可阅读torch源码),所以两者功能并无区别,那么为什么要有这样的两种实现方式同时存在呢?

原因其实在于,为了兼顾灵活性和便利性。

在建图过程中,往往有两种层,一种如全连接层,卷积层等,当中有Variable,另一种如Pooling层,Relu层等,当中没有Variable。

如果所有的层都用nn.functional来定义,那么所有的Variable,如weights,bias等,都需要用户来手动定义,非常不方便。

而如果所有的层都换成nn来定义,那么即便是简单的计算都需要建类来做,而这些可以用更为简单的函数来代替的。
所以在定义网络的时候,如果层内有Variable,那么用nn定义,反之,则用nn.functional定义。

'''



 

本地加载数据:

Pytorch关于CIFAR-10测试-LMLPHP 

Pytorch关于CIFAR-10测试-LMLPHP 

CPU下训练:

import time
import torch.optim.optimizer
import torchvision
from torch import nn, optim
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from 练习 import Model  # 导入CIFAR_model.py里的Model类定义

# 1.创建 CIFAR10 数据集的训练和测试实例
#实现本地加载
train_data = torchvision.datasets.CIFAR10(root="../data/CIFAR-10/", train=True,
                                          transform=torchvision.transforms.ToTensor(),
                                          download=False)
test_data = torchvision.datasets.CIFAR10(root="../data/CIFAR-10/", train=False,
                                         transform=torchvision.transforms.ToTensor(),
                                         download=False)

# 2.利用 DataLoader 加载数据集
train_dataloader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

# 3.搭建神经网络:CIFAR-10
model = Model()  # 创建实例

# 4.损失函数
loss = nn.CrossEntropyLoss()

# 5.优化器
learning_rate = 0.01
optimizer = torch.optim.SGD(model.parameters(), learning_rate)

# 6.设置训练网络的一些参数
total_train_step = 0  # 记录训练的次数
total_test_step = 0  # 记录测试的次数
epoch = 10  # 训练的轮数

for i in range(epoch):
    print(f"--------第{i}轮训练开始--------")

    # 训练步骤开始
    model.train()  # 模型进入训练模式
    for data in train_dataloader: #获取图片和对应的标签
        imgs, targets = data
        outputs = model(imgs) #模型输入图片
        result_loss = loss(outputs, targets)  # 计算每个参数对应的损失

        # 优化器优化模型
        optimizer.zero_grad()  # 每个参数对应的梯度清零
        result_loss.backward()  # 反向传播,计算每个参数对应的梯度
        optimizer.step()  # 每个参数根据上一步得到的梯度进行优化

        total_train_step += 1
        if total_train_step % 100 == 0:
            end_time = time.time()  # 结束时间
            print(f"训练次数:{total_train_step},Loss:{result_loss.item()}")

    # 测试步骤开始(每轮训练好、但不进行优化的模型)
    model.eval()  # 模型进入测试模式(仅针对有Dropout,BatchNorm层的网络结构)
    total_test_loss = 0  #计算总的梯度损失
    total_accuracy = 0   #将准确度加起来,计算平均准确度
    with torch.no_grad():  # 不需要计算梯度,直接将数据放入网络进行测试
        for data in test_dataloader:
            imgs, targets = data
            outputs = model(imgs)
            result_loss = loss(outputs, targets)
            total_test_loss += result_loss  # 损失累加

            # 计算标签正确数(取得在 1 方向,概率最大的索引,即得标签输出值;对比标签输出值与目标值+求和:True=1,False=0)
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy += accuracy

    print(f"整体测试集上的Loss:{total_test_loss}")
    print(f"整体测试集上的正确率:{total_accuracy / len(test_data)}")
    total_test_step += 1
    torch.save(model, f"CIFAR_model_{i}.pth")
    print("模型已保存!")


 添加GPU测试:

搭建神经网络:CIFAR-10模型
model = Model()  # 创建实例
if torch.cuda.is_available():  # GPU是否可用
    print("使用GPU训练")
    model = model.cuda()  # GPU(非必须重赋值)
    # model.cuda()  # 与上一句效果一样,不用重赋值


损失函数
loss_fn = nn.CrossEntropyLoss()
if torch.cuda.is_available():  # GPU是否可用
    loss_fn = loss_fn.cuda()  # GPU(非必须重赋值)


for data in train_dataloader:
        imgs, targets = data
        if torch.cuda.is_available():  # GPU是否可用
            imgs = imgs.cuda()  # GPU(必须重赋值)
            targets = targets.cuda()  # GPU(必须重赋值)
        outputs = model(imgs)



 with torch.no_grad():  # 不进行优化的
        for data in test_dataloader:
            imgs, targets = data
            if torch.cuda.is_available():  # GPU是否可用
                imgs = imgs.cuda()  # GPU(必须重赋值)
                targets = targets.cuda()  # GPU(必须重赋值)
            outputs = model(imgs)
# 定义训练的设备GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")  # ”cuda:0“ 等效 ”cuda“
print(device)


搭建神经网络:CIFAR-10模型
model = Model()  # 创建实例
model = model.to(device)  # GPU(非必须重赋值)
# model.to(device)  # 与上一句效果一样,不用重赋值


损失函数
loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.to(device)  # GPU(非必须重赋值)




for data in train_dataloader:
        imgs, targets = data
        imgs = imgs.to(device)  # GPU
        targets = targets.to(device)  # GPU
        outputs = model(imgs)



with torch.no_grad():  # 不进行优化的
        for data in test_dataloader:
            imgs, targets = data
            imgs = imgs.to(device)  # GPU
            targets = targets.to(device)  # GPU
            outputs = model(imgs)

 加载模型进行预测结果:

import torch
import torchvision
from PIL import Image
from CIFAR_model import Model  # 导入CIFAR_model.py里的Model类定义

image_path = "./boss.png"
image = Image.open(image_path)  # 加载3通道的图片数据,3阶张量
print(image)  # <PIL.Image.Image image mode=RGB size=352x261 at 0x1E61DE1FE50>

# 将图片 Resize(缩放) 到32x32尺寸,适合模型输入,最后在转化为Tensor实例
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32, 32)),
                                            torchvision.transforms.ToTensor()])
image = transform(image)
# 转化为4阶张量(模型网络的输入要求张量的阶数为4)
image = torch.reshape(image, (1, 3, 32, 32))
print(image.shape)  # torch.Size([1, 3, 32, 32])

# -----------------1.测试方式a(常用,CPU上测试)-----------------
print("\nCPU上测试:")
# 加载训练好的模型
# 采用GPU训练的模型,要想在CPU上测试,必须映射到CPU上(或者模型不用映射到CPU上,而图片映射到GPU上)
model = torch.load("CIFAR_model_9.pth", map_location=torch.device("cpu"))
# print(model)

model.eval()   # 模型进入测试模式(仅针对有Dropout,BatchNorm层的网络结构)
with torch.no_grad():  # 有利于节约内存和性能
    output = model(image)
print(output)
print(output.argmax(1))  # 方向1最大值的索引值




# -----------------2.测试方式b(GPU上测试)-----------------
print("\nGPU上测试:")
# 加载训练好的模型
model = torch.load("CIFAR_model_9.pth")
# print(model)

model.eval()   # 模型进入测试模式(仅针对有Dropout,BatchNorm层的网络结构)
with torch.no_grad():  # 有利于节约内存和性能
    # 将图片放到GPU上运行(采用GPU训练的模型,图片应该放到GPU上)
    output = model(image.cuda())
    # output = model(image.to("cuda:0"))  # 等效于上一句
print(output)
print(output.argmax(1))  # 方向1最大值的索引值
02-20 09:40