图像分类之LeNet网络

前言

LeNet是最早的卷积神经网络之一,并且推动了深度学习领域的发展。自从1988年开始,这项由Yann LeCun完成的开拓性成果被命名为LeNet5。这个网络也是深度学习的入门要学的第一个网络。

网络主要部分

1、model.py ------ 模型的架构
2、train.py ——加载数据集并训练,训练集计算loss,测试集计算accuracy,保存训练好的网络参数
3、predict.py——得到训练好的网络参数后,随便找一张cifar10的图像进行分类测试

1、model.py

# 使用torch.nn包构建神经网络
import torch.nn as nn
import torch.nn.functional as F

# 定义LeNet网络
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 16, 5) # 3代表输入通道,16个卷积核,卷积核大小为5
        self.pool1 = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(16, 32, 5)
        self.pool2 = nn.MaxPool2d(2, 2)
        self.fc1 = nn.Linear(32*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = F.relu(self.conv1(x))    # input(3, 32, 32) output(16, 28, 28)
        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)
        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)
        return x

在这里插入图片描述

每一层详解

(1)INPUT层—输入层
首先是数据输入层,输入大小为32×32的图片。
(2)C1卷积层
输入图片大小:32×32
卷积核大小:5×5
卷积核个数:16
输出featuremap大小:2828 (32-5+1)=28
可训练参数:(5
5+1) * 6(每个滤波器55=25个unit参数和一个bias参数,一共6个滤波器)
连接数:(5
5+1)62828=122304
(3)S2池化层(下采样)
输入:28×28
采样区域:2×2
输出featureMap大小:14×14(28/2)
(4)C3卷积层
输入:S2中所有6个或者几个特征map组合
卷积核大小:5×5
卷积核种类:16
输出featureMap大小:10×10 (14-5+1)=10
(5)S4池化层(下采样)
输入:10×10
采样区域:2×2
采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果通过sigmoid
采样种类:16
输出featureMap大小:5×5(10/2)
神经元数量:5×5×16=400
可训练参数:2×16=32
连接数:16×(2×2+1)×5×5=2000
(6)C5卷积层
输入:S4层的全部16个单元特征map(与s4全相连)
卷积核大小:5×5
卷积核种类:120
输出featureMap大小:1×1(5-5+1)
可训练参数连接:120
(1655+1)=48120
(7)F6全连接层
输入:c5 120维向量
计算方式:计算输入向量和权重向量之间的点积,再加上一个偏置,结果通过sigmoid函数输出。
可训练参数:84*(120+1)=10164
(8)OUTPUT层–全连接层
Output层也是全连接层,共有10个节点,分别代表数字0到9,且如果节点i的值为0,则网络识别的结果是数字i

2、train.py

导入数据集

# 导入各种包
import torch
import torchvision
import torch.nn as nn
from model import LeNet
import torch.optim as optim
import torchvision.transforms as transforms

对数据进行处理

transform = transforms.Compose(  # transforms.Compose()主要作用是串联多个图片变换的操作
        # ToTensor() 能够把灰度范围从0-255变换到0-1之间,而后面的transform.Normalize()则把0-1变换到(-1,1).
        # 具体地说,对每个通道而言,Normalize执行以下操作:
        # image=(image-mean)/std
        # 其中mean和std分别通过(0.5,0.5,0.5)和(0.5,0.5,0.5)进行指定。原来的0-1最小值0则变成(0-0.5)/0.5=-1,而最大值1则变成(1-0.5)/0.5=1.
        # 而transforms.Compose()负责将这两个对图像的操作串联起来。
        [transforms.ToTensor(), # convert a "PIL Image" or "numpy.ndarray(H×W×C)" to tensor(C×H×W) in the range[0.0,1.0]
         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) # 标准化的过程

导入、加载训练集

# 50000张训练图片
    # 第一次使用时要将download设置为True才会自动去下载数据集,下载好后改为False
    train_set = torchvision.datasets.CIFAR10(root='./data', train=True,
                                             download=True, transform=transform)
    # 分批次训练,每批次随机拿出36个图片进行训练,shuffle=True表示对数据进行打乱
    train_loader = torch.utils.data.DataLoader(train_set, batch_size=36,
                                               shuffle=True, num_workers=0)

导入、加载测试集

# 10000张验证图片
    # 第一次使用时要将download设置为True才会自动去下载数据集
    # torchvision.datasets: 一些加载数据的函数及常用的数据集接口
    val_set = torchvision.datasets.CIFAR10(root='./data', train=False,
                                           download=False, transform=transform)
    # torch.utils.data.DataLoader()的作用就是实现数据以什么方式输入到什么网络中,训练数据的加载器
    val_loader = torch.utils.data.DataLoader(val_set, batch_size=5000,
                                             shuffle=False, num_workers=0)
     # 获取测试集中的图像和标签,用于accuracy计算
    val_data_iter = iter(val_loader) # 转换为迭代器
    val_image, val_label = val_data_iter.next()  # 通过next()获得一批数据,数据中包含了图像以及图像对应的标签值

训练过程

net = LeNet() # 实例化模型
    loss_function = nn.CrossEntropyLoss() # 损失函数
    optimizer = optim.Adam(net.parameters(), lr=0.001) # 优化器

    # 训练过程
    for epoch in range(5):  # loop over the dataset multiple times

        running_loss = 0.0  # 累加迭代过程中的损失
        for step, data in enumerate(train_loader, start=0):
            # get the inputs; data is a list of [inputs, labels]
            inputs, labels = data

            # zero the parameter gradients
            optimizer.zero_grad()
            # forward + backward + optimize
            outputs = net(inputs)
            loss = loss_function(outputs, labels)
            loss.backward() # 反向传播
            optimizer.step()

            # print statistics
            running_loss += loss.item()
            if step % 500 == 499:    # print every 500 mini-batches
                with torch.no_grad():  # 不用计算误差梯度
                    outputs = net(val_image)  # [batch, 10]
                    predict_y = torch.max(outputs, dim=1)[1]
                    accuracy = torch.eq(predict_y, val_label).sum().item() / val_label.size(0)

                    print('[%d, %5d] train_loss: %.3f  test_accuracy: %.3f' %
                          (epoch + 1, step + 1, running_loss / 500, accuracy))
                    running_loss = 0.0

    print('Finished Training')

    save_path = './Lenet.pth'
    torch.save(net.state_dict(), save_path)


if __name__ == '__main__':
    main()

打印信息如下:

[1,  1000] train_loss: 1.537  test_accuracy: 0.541
35.345407 s
[2,  1000] train_loss: 1.198  test_accuracy: 0.605
40.532376 s
[3,  1000] train_loss: 1.048  test_accuracy: 0.641
44.144097 s
[4,  1000] train_loss: 0.954  test_accuracy: 0.647
41.313228 s
[5,  1000] train_loss: 0.882  test_accuracy: 0.662
41.860646 s
Finished Training

3、predict.py

# 导入包
import torch
import torchvision.transforms as transforms
from PIL import Image

from model import LeNet

# 数据预处理
def main():
    transform = transforms.Compose(
        [transforms.Resize((32, 32)), # 把给定的图片resize到和训练集图片相同大小
         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()
    net.load_state_dict(torch.load('Lenet.pth'))  # 载入权重文件
    
    # 导入要测试的图像,是自己找的
    im = Image.open('1.jpg')
    im = transform(im)  # [C, H, W]
    im = torch.unsqueeze(im, dim=0)  # [N, C, H, W] 增加一个维度,

    # 预测
    with torch.no_grad():
        outputs = net(im)
        predict = torch.max(outputs, dim=1)[1].data.numpy()
    print(classes[int(predict)])


if __name__ == '__main__':
    main()

输出为预测结果
这是本人在学习过程中的一些学习笔记,希望能给大家带来帮助,有不对的地方还请各位大神指教~
参考资料:https://blog.csdn.net/m0_37867091/article/details/107136477
https://blog.csdn.net/qq_42570457/article/details/81460807?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163719754416780269827865%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=163719754416780269827865&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-81460807.first_rank_v2_pc_rank_v29&utm_term=lenet&spm=1018.2226.3001.4187

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值