Lenet-pytorch官方demo

1、pytorch安装

通过anaconda安装pythorch参考的这篇

2、Lenet简介

Lenet网络结构:卷积-下采样层-卷积-下采样层-全连接层-全连接层-全连接层
Lenet网络:pytorch tensor的通道顺序:[batch,channel,height,width]

batch:每一批的数量
channel:通道的数量,对于彩色图片有RGB三个通道,channel=3
在这里插入图片描述

3、代码

Conv2d和_MaxPoolNd参数介绍

  1. pytorch通过Conv2d定义卷积层
    Conv2d各个参数(Pycharm中通过Ctrl+单击查看)
def __init__(
        self,
        in_channels: int,	# 输入特征矩阵的深度
        out_channels: int,	# 使用卷积核的个数
        kernel_size: _size_2_t,	# 卷积核大小
        stride: _size_2_t = 1,	# 步距,默认=1
        padding: _size_2_t = 0,	#在四周补0处理,默认=0
        dilation: _size_2_t = 1,
        groups: int = 1,
        bias: bool = True,	# 偏执,默认使用
        padding_mode: str = 'zeros'  # TODO: refine this type
    ):
  1. pytorch通过MaxPool2d定义下采样层
    MaxPool2d继承了父类_MaxPoolNd
    _MaxPoolNd各个参数
def __init__(self, kernel_size: _size_any_t, stride: Optional[_size_any_t] = None,
             padding: _size_any_t = 0, dilation: _size_any_t = 1,
             return_indices: bool = False, ceil_mode: bool = False) -> None:
    super(_MaxPoolNd, self).__init__()
    self.kernel_size = kernel_size	# kernel_size池化和大小
    self.stride = stride or kernel_size	# 步距,未指定步距就与池化和大小一致
    self.padding = padding
    self.dilation = dilation
    self.return_indices = return_indices
    self.ceil_mode = ceil_mode

model.py

import torch.nn as nn
import torch.nn.functional as F


class LeNet(nn.Module):
    # 初始化函数 搭建所需要的网络层结构
    def __init__(self):
        super(LeNet, self).__init__()
        # 第一个卷积层conv1
        # Conv2d第一个参数=3代表输入特征层的深度(RGB3个通道)
        # Conv2d第二个参数=16表示使用的卷积核的个数=16
        # Conv2d第三个参数=5表示卷积核的尺寸是5*5
        self.conv1 = nn.Conv2d(3, 16, 5)

        # 第一个下采样层pool1
        # 池化和大小为2*2,步距=2
        self.pool1 = nn.MaxPool2d(2, 2)

        # 第二个卷积层
        self.conv2 = nn.Conv2d(16, 32, 5)

        # 第二个下采样层pool1
        # 池化和大小为2*2,步距=2
        self.pool2 = nn.MaxPool2d(2, 2)

        # 开始全连接层
        # 全连接层输入为一维向量
        self.fc1 = nn.Linear(32*5*5, 120)   # 第一个全连接层
        self.fc2 = nn.Linear(120, 84)   # 第二个全连接层

        # 输出根据训练集来选择,本例具有10个分类类别,选择10
        self.fc3 = nn.Linear(84, 10)    # 第三个全连接层

    # 正向传播过程
    def forward(self, x):
        # 第一个卷积层
        # input(3, 32, 32) output(16, 28, 28)
        # 根据公式N=(W-F+2*P)/S+1计算经卷积之后的矩阵尺寸大小
        # 已知输入特征的高和宽W=32,卷积核的大小F=5,padding默认P=0,stride=1
        # 故N=(32-5)/1+1=28,且使用的卷积核的个数=16,故output(16, 28, 28)
        x = F.relu(self.conv1(x))

        # 第一个下采样层
        # 经过池化和之后,高度和宽度缩小为原来一半28/2,深度不变
        x = self.pool1(x)            # output(16, 14, 14)

        # 第二个卷积层
        x = F.relu(self.conv2(x))    # output(32, 10, 10)
        # 第二个下采样层
        x = self.pool2(x)            # output(32, 5, 5)

        # 开始和全连接层拼接
        # .view展成一维的,-1是因为LeNet的tensor第一维的参数是batch,自动推理
        x = x.view(-1, 32*5*5)       # output(32*5*5)
        x = F.relu(self.fc1(x))      # output(120)
        x = F.relu(self.fc2(x))      # output(84)
        x = self.fc3(x)              # output(10)
        # 由于在计算损失交叉熵的过程中已经实现了更加高效的softmax方法,因此不需要添加softmax层了
        return x

# 测试
# import torch
# input1 = torch.rand([32, 3, 32, 32])
# model =LeNet()
# print(model)
# output = model(input1)

train.py

import numpy as np
import torch
import torchvision
import torch.nn as nn
from model import LeNet
import torch.optim as optim
import torchvision.transforms as transforms
import matplotlib.pyplot as plt

def main():
    transform = transforms.Compose(# Compose将所使用的预处理方法(ToTensor()和Normalize)打包成一个整体
        [transforms.ToTensor(),     # 预处理
         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])   #标准化,使用均值和标准差来标准化

    # 50000张训练图片
    # 第一次使用时要将download设置为True才会自动去下载数据集(导入数据集)
    train_set = torchvision.datasets.CIFAR10(root='./data', train=True,
                                             download=False, transform=transform)
    # 把train_set导入进来,并分成一个批次一个批次的,shuffle是否将数据集打乱
    train_loader = torch.utils.data.DataLoader(train_set, batch_size=36,
                                               shuffle=True, num_workers=0)

    # 10000张验证图片
    # 第一次使用时要将download设置为True才会自动去下载数据集
    val_set = torchvision.datasets.CIFAR10(root='./data', train=False,
                                           download=False, transform=transform)
    val_loader = torch.utils.data.DataLoader(val_set, batch_size=10000,
                                             shuffle=False, num_workers=0)  #num_workers在Windows下只能=0
    # 将val_loader转化成可迭代的迭代器
    val_data_iter = iter(val_loader)
    val_image, val_label = val_data_iter.next()     # 使用next获取图像以及图像的标签值,获取全部图像10000张

    # 导入标签
    classes = ('plane', 'car', 'bird', 'cat',
               'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

# 简单查看测试集中的4张图片,需要把val_loader的batch_size改成=4
# def imshow(img):
#     img = img / 2 + 0.5     # unnormalize 反标准化处理
#     npimg = img.numpy()
#     plt.imshow(np.transpose(npimg, (1, 2, 0)))
#     plt.show()
#
# # print labels
# print(' '.join('%5s' % classes[val_label[j]] for j in range(4)))
# # show images
# imshow(torchvision.utils.make_grid(val_image))


    net = LeNet()   # 实例化模型
    # 定义损失函数,CrossEntropyLoss已经包含了softmax函数了
    loss_function = nn.CrossEntropyLoss()
    # 使用Adam优化器,第一个参数为需要训练的参数,此例为LeNet的所有参数;学习率lr=0.001
    optimizer = optim.Adam(net.parameters(), lr=0.001)

    # 训练集迭代5次
    for epoch in range(5):  # loop over the dataset multiple times

        running_loss = 0.0    # 累加损失
        # 遍历训练集样本
        # 使用enumerate函数,不仅会返回每一批的data,还对返回相应的索引,start=0从0开始
        for step, data in enumerate(train_loader, start=0):
            # get the inputs; data is a list of [inputs, labels]
            # 将得到的数据分为inputs和对应的标签labels
            inputs, labels = data

            # zero the parameter gradients
            # 将历史损失梯度函数清零,帮助实现很大的batch训练
            optimizer.zero_grad()

            # forward + backward + optimize
            # 将所有图片inputs输入到网络中进行正向传播
            outputs = net(inputs)

            # 计算损失,outputs是网络预测值,labels是对应的真实标签
            loss = loss_function(outputs, labels)

            # 将loss进行反向传播
            loss.backward()

            # 通过优化器的函数进行参数更新
            optimizer.step()

            # print statistics打印
            running_loss += loss.item()
            # 每训练500次打印一次
            if step % 500 == 499:    # print every 500 mini-batches
                with torch.no_grad():   # 在接下来的计算中不计算每个节点的误差损失梯度,避免占用更多的算力
                    outputs = net(val_image)  # [batch, 10]正向传播

                    # 寻找输出的最大的index 由于第0个维度对应的是batch,故选择dim=1,从10个类别中寻找最大
                    predict_y = torch.max(outputs, dim=1)[1]    # [1]表示只需index值既可,不需要知道具体值

                    # 判断预测的label和实际的label是否相等
                    # 通过sum求和预测对了多少样本(此时得到的是Tensor)
                    # 通过.item()拿到对应的数值,再除训练样本的个数
                    accuracy = (predict_y == val_label).sum().item() / val_label.size(0)

                    # epoch训练迭代的轮数,在某一轮的多少步,训练过程中累加的误差/500得到平均误差,测试样本的准确率
                    print('[%d, %5d] train_loss: %.3f  test_accuracy: %.3f' %
                          (epoch + 1, step + 1, running_loss / 500, accuracy))
                    # 将损失误差清零开始下一轮500步的迭代
                    running_loss = 0.0

    print('Finished Training')

    save_path = './Lenet.pth'
    torch.save(net.state_dict(), save_path)# 模型的参数进行保存


if __name__ == '__main__':
    main()

predict.py

import torch
import torchvision.transforms as transforms
from PIL import Image
from model import LeNet

transform = transforms.Compose(
    [transforms.Resize((32, 32)),
     transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

net = LeNet()   # 实例化LeNet
net.load_state_dict(torch.load('Lenet.pth'))    # 载入训练生成的权重文件

# 载入图像
im = Image.open('1.jpg')
im = transform(im)  # [C, H, W]预处理成pytorch能处理的tensor格式
im = torch.unsqueeze(im, dim=0)  # [N, C, H, W]加上一个新维度batch

with torch.no_grad():
    outputs = net(im)
    #predict = torch.max(outputs, dim=1)[1].data.numpy()#取到最大的index,赋值给predict
    predict = torch.softmax(outputs,dim=1)  # 对第一个维度进行处理,第0维为batch
print(predict)
#print(classes[int(predict)])   # 将index传入classes

目录结构
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值