LeNet-5 数字图像识别

1.LeNet-5的基本结构

输入 → 卷积 → 池化 → 卷积 → 池化 → 卷积(全连接) → 全连接 → 输出。

包括7层网络结构(不含输入层)

1、输入层(Input layer)

接收32*32的手写数字图像,包括灰度值(0-255),在实际应用中,我们通常会对输入图像进行预处理,例如对像素值进行归一化,以加快训练速度和提高模型的准确性,

2、卷积层C1(Convolutional layer C1)

包括6个卷积核,每个卷积核的大小为5*5,步长为1,填充为0,输出上使用sigmoid激活函数,

每个卷积核产生一个大小为28*28的特征图,(输出通道数为6)

3、采样层S2(Subsampling layer S2)

采用最大池化(max-pooling)操作,每个窗口的大小为2*2,步长为2,产生一个14*14的特征图,(输出通道数为6)。

这样可以减少特征图的大小,提高计算效率,并且对于轻微的位置变化可以保持一定的不变性

4、卷积层C3(Convolutional layer C3)

包括16个卷积核,每个卷积核的大小为5*5,步长为1,填充为0。输出上使用sigmoid激活函数,

每个卷积核会产生一个大小为10*10的特征图(输出通道数为16)

5、采样层S4(Subsampling layer S4)

采用最大池化(max-pooling)操作,每个窗口的大小为2*2,步长为2,产生一个5*5的特征图,(输出通道数为16)

6、全连接层C5(Fully connected layer C5)

将每个5*5的特征图(共16个)成一个长度为400的向量,并通过一个带有120个神经元的全连接层进行连接。

120是由LeNet-5的设计者根据实验得到的最佳值

7、全连接层F6(Fully connected layer F6)

将120个神经元连接到84个神经元上

8、输出层(Output layer)

由10个神经元组成,每个神经元对应0-9中的一个数字,并输出最终的分类结果

2.特征图大小的计算

3.代码实现 

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.datasets as datasets
import torchvision.transforms as transforms

'''定义LeNet-5模型'''
class LeNet5(nn.Module):
    def __init__(self):
        super(LeNet5, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, stride=1)
        self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5, stride=1)
        self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2)
        self.fc1 = nn.Linear(in_features=16 * 4 * 4, out_features=120)
        self.fc2 = nn.Linear(in_features=120, out_features=84)
        self.fc3 = nn.Linear(in_features=84, out_features=10)
        
    def forward(self, x):
        x = self.pool1(torch.relu(self.conv1(x)))
        # 1.通过卷积层self.conv1进行卷积操作
        # 2.使用ReLU激活函数torch.relu对结果进行非线性变换
        # 3.通过池化层self.pool1对得到的特征图进行下采样
        x = self.pool2(torch.relu(self.conv2(x)))
        x = x.view(-1, 16 * 4 * 4)
        # 调用x.view(-1, 16 * 4 * 4)将特征张量展平成一维向量,以便输入全连接层self.fc1进行处理
        x = torch.relu(self.fc1(x)) #使用ReLU激活函数对fc1的输出进行非线性变换
        x = torch.relu(self.fc2(x)) #使用ReLU激活函数对fc2的输出进行非线性变换
        x = self.fc3(x) #通过全连接层self.fc3获得最终的输出结果
        return x

net = LeNet5()
print(net)

import torchvision.transforms as transforms
'''加载MNIST数据集'''
# transform = torchvision.transforms.ToTensor()   #定义数据预处理方式:转换 PIL.Image 成 torch.FloatTensor
train_dataset = datasets.MNIST(root='./data',           #数据目录,
                               train=True,              #是否为训练集
                               transform=transforms.ToTensor(),    #加载数据预处理
                               download=True)            #是否下载
test_dataset = datasets.MNIST(root='./data', 
                              train=False, 
                              transform=transforms.ToTensor(),
                              download=False)

# 定义数据加载器
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)

'''观察部分MNIST数据集'''
import numpy as np
import matplotlib.pyplot as plt
def imshow(img):
     img = img / 2 + 0.5 # unnormalize
     npimg = img.numpy()
     plt.imshow(np.transpose(npimg, (1, 2, 0)))
     plt.show()

# torchvision.utils.make_grid 将图片进行拼接
imshow(torchvision.utils.make_grid(iter(train_loader).next()[0]))

 

'''定义模型、损失函数和优化器'''
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') #设置GPU运行
net = LeNet5().to(device)  #实例化网络,有GPU则将网络放入GPU加速
loss = nn.CrossEntropyLoss()  #多分类问题,选择交叉熵损失函数
optimizer = optim.SGD(net.parameters(),lr = 0.001,momentum = 0.9)   #选择SGD,学习率取0.001


'''训练模型'''
num_epochs = 10
for epoch in range(num_epochs):
    sum_loss = 0
    for i, (images, labels) in enumerate(train_loader):
        images,labels = images.to(device), labels.to(device)   #有GPU则将数据置入GPU加速
        '''梯度清零'''
        optimizer.zero_grad()
        '''传递损失 + 更新参数'''
        outputs =net(images)
        l = loss(outputs, labels)
        l.backward()
        optimizer.step()
        
        '''每训练100个batch打印一次平均loss'''
        sum_loss += l.item()
        if (i) % 100 == 99:
            # print('[Epoch:%d, batch:%d] train loss: %.03f' % (epoch + 1, i + 1, sum_loss / 100))
            sum_loss = 0.0
            

    '''测试模型'''
    net.eval()
    with torch.no_grad():
        correct = 0
        total = 0
        for data in test_loader:
                test_inputs, labels = data
                test_inputs, labels = test_inputs.to(device), labels.to(device)
                outputs_test = net(test_inputs)
                _, predicted = torch.max(outputs_test.data, 1)  #输出得分最高的类
                total += labels.size(0) #统计50个batch 图片的总个数
                correct += (predicted == labels).sum()  #统计50个batch 正确分类的个数
        print('第{}个epoch的识别准确率为:{}%'.format (epoch + 1, 100*correct.item()/total))
    

#模型保存
torch.save(net, './model/LeNet5.bin')

#模型加载
# net2 = torch.load('./model/LeNet5.bin')
# print(net2)

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeNet-5是一种经典的卷积神经网络,用于手写数字的识别。它在1998年由Yann LeCun等人提出,旨在通过学习感知到的局部特征来实现数字的自动识别和分类。 LeNet-5主要由两个重要部分组成:卷积神经网络(CNN)和全连接层。 输入图像首先经过两个卷积层和池化层,用于提取图像的特征。卷积层通过滑动窗口计算每个窗口中的特征,然后池化层对特征图进行降采样,减少计算量和参数个数。随后,通过几个全连接层对提取的特征进行分类,最终输出层得到识别结果。 在训练阶段,LeNet-5使用反向传播算法来更新网络权重,最小化训练样本与目标标签之间的损失函数。该损失函数可衡量网络对不同数字的分类准确性。 为了识别手写数字'c',我们需要准备一组训练样本包含手写数字'c'的图像及其标签,并将这些样本输入LeNet-5进行训练。训练过程中,网络将学习到特定于'c'的特征,以便能够准确地区分出'c'与其他数字。 完成训练后,我们可以用测试集对LeNet-5进行评估。将手写数字'c'的图像输入网络,根据输出层的预测结果即可进行识别判断。如果网络的输出结果与'c'标签匹配,则说明LeNet-5成功地识别了手写数字'c'。 总而言之,LeNet-5是一种使用卷积神经网络实现手写数字识别的经典模型。通过训练和调整网络权重,LeNet-5能够识别手写数字'c'。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值