CNN典型模型及pytorch实现 —— LeNet

LeNet是于1989年提出的一种网络结构,目前在各大深度学习框架中使用的是简化版的LeNet-5,与原始的结构区别在于把激活函数换成了ReLU;

LeNet奠定了卷积层+池化层+全连接层的结构,初用于手写数字的识别问题,输入为单通道的灰度图;

LeNet网络结构图

在这里插入图片描述

第一层:输入层
输入层是32 * 32大小的图像(Mnist数据库为28 * 28大小),目的是希望潜在的明显特征出现在最高层特征监视子感受野的中心;

Mnist数据集包括70,000个样本,其中训练集包括60,000个样本,测试集包括10,000个样本,训练集与测试集中书写体与手写体的数字(0~9)各占一半;

C1层是卷积层
6个特征图谱(feature map),5 * 5大小的卷积核;
每个feature map有(32 - 5 + 1)*(32 - 5 + 1)个神经元;
每个神经元与输入层的5 * 5大小的区域相连,所以C1层每个神经元有(5 * 5 + 1)*6个训练参数(5 * 5个连接参数核=和一个偏置参数);
通过卷积运算使原信号特征增强,并降低噪音;
不同卷积核能提取到图像不同特征;

S2层是下采样层
6个14 * 14特征图;
每个feature map中的每个神经元与C1层对应的feature map中的2 * 2区域相连,S2中每个神经元由这四个输入相加,乘以一个训练参数,再加上这个feature map的偏置参数,结果通过sigmoid函数计算而得;
S2的每个feature map由14 * 14个神经元;
参数个数为(1 + 1)* 6 = 12个;
连接数为(4 + 1)*(14 * 14)*6 = 5880个;
池化层的目的是为了降低网络训练参数及模型的过拟合程度;
池化方式有最大池化、平均池化;

C3层是一个卷积层
16个feature map,5 * 5大小的卷积核;
每个feature map有(14- 5 + 1)*(14 - 5 + 1)个神经元;
每个feature map由上一层的各feature map之间的不同组合;

S4层是下采样层
由16个5 * 5大小的feature map组成;
每个神经元与C3层对应的feature map中的2 * 2区域相连;
参数个数为(1 + 1)* 16 = 32个;
连接数为(4 + 1)*(5 * 5)*6 = 2000个(连接数大大降低了);

C5是一个卷积层
120个feature map,5 * 5大小的卷积核;
每个feature map有(5- 5 + 1)*(5 - 5 + 1)个神经元;
每个单元都与S4层的全部16个feature map的5 * 5区域相连;

F6层是全连接层
共有84个feature map;
每个feature map只有一个神经元与C5层全连接;
有(1 * 1 *120 + 1)*84 = 10164个参数和连接;
计算输入向量和权重向量之间的点积和偏置,传递给sigmoid函数计算神经元;

输出层
输出层也是全连接层;
共有10个节点,分别代表数字0 ~ 9(如果节点i的值为0,则该网络的识别结果为数字i);
输出的计算方式为(径向基函数RBF):
在这里插入图片描述
所以输出越接近0,则越接近i的比特图编码,即表示当前网络输入的识别结果为i。

LeNet模型代码(Pytorch)

import torch
import torchvision
import torch.utils.data as Data
from torch import nn
from torch.autograd import Variable

BATCH_SIZE = 50
LOAD_DOWN = False
LR = 0.001
EPOCH = 1


# 搭建LeNet网络
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(1, 6, 5, 1, 2, bias=True),
            nn.MaxPool2d(2)
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(6, 16, 5, 1, 2, bias=True),
            nn.MaxPool2d(2)
        )
        self.conv3 = nn.Sequential(
            nn.Conv2d(16, 120, 5, 1, 2, bias=True)
        )
        self.fc = nn.Linear(120*7*7, 84)
        self.predict = nn.Linear(84, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        x = torch.sigmoid(x)
        output = self.predict(x)
        return output


# 训练集
train_data = torchvision.datasets.MNIST(
    root='./mnist',
    train=True,
    transform=torchvision.transforms.ToTensor(),
    download=LOAD_DOWN
)
train_loader = Data.DataLoader(
    dataset=train_data,
    batch_size=BATCH_SIZE,
    shuffle=True
)

# 测试集
test_data = torchvision.datasets.MNIST(
    root='./mnist',
    train=False,
)
x_test = torch.unsqueeze(test_data.test_data, dim=1)
x_test = Variable(x_test).type(torch.FloatTensor)[:1000]/255
y_test = test_data.test_labels.data.numpy()[:1000]

# 实例化
lenet = LeNet()
optimizer = torch.optim.Adam(lenet.parameters(), lr=LR)
loss_func = nn.CrossEntropyLoss()

# 训练
for epoch in range(EPOCH):
    for step, (x, y) in enumerate(train_loader):
        b_x = Variable(x)
        b_y = Variable(y)

        prediction = lenet(b_x)
        loss = loss_func(prediction, b_y)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        # 测试
        if step % 50 == 0:
            pred_out = lenet(x_test)
            pred_out = torch.max(pred_out, 1)[1].data.numpy().squeeze()   # 只返回每行最大值元素所在行的索引
            accuracy = sum(pred_out == y_test) / y_test.size
            print('loss:', loss.data.numpy(), '| accuracy:', accuracy)
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值