LeNet网络在pytorch下的实现

2.LeNet网络结构

3.LeNet网络数据导入

       1.从网络上下载

        2.本地加载

4.LeNet网络结构在pytorch下的实现

5.定义参数

6.训练部分

7.测试部分

8.训练结果

1.LeNet介绍

LeNet5 这个网络虽然很小,但是它包含了深度学习的基本模块:卷积层,池化层,全连接层。是其他深度学习模型的基础, 这里我们对LeNet5进行深入分析。同时,通过实例分析,加深对与卷积层和池化层的理解。

2.LeNet网络结构

 LeNet-5共有7层,不包含输入,每层都包含可训练参数;每个层有多个Feature Map,每个FeatureMap通过一种卷积滤波器提取输入的一种特征,然后每个FeatureMap有多个神经元。

1、INPUT层-输入层

首先是数据 INPUT 层,输入图像的尺寸统一归一化为32*32。

注意:本层不算LeNet-5的网络结构,传统上,不将输入层视为网络层次结构之一。

2、C1层-卷积层

输入图片:32*32

卷积核大小:5*5

卷积核种类:6

输出featuremap大小:28*28 (32-5+1)=28

神经元数量:28*28*6

可训练参数:(5*5+1) * 6(每个滤波器5*5=25个unit参数和一个bias参数,一共6个滤波器)

连接数:(5*5+1)*6*28*28=122304

详细说明:对输入图像进行第一次卷积运算(使用 6 个大小为 5*5 的卷积核),得到6个C1特征图(6个大小为28*28的 feature maps, 32-5+1=28)。我们再来看看需要多少个参数,卷积核的大小为5*5,总共就有6*(5*5+1)=156个参数,其中+1是表示一个核有一个bias。对于卷积层C1,C1内的每个像素都与输入图像中的5*5个像素和1个bias有连接,所以总共有156*28*28=122304个连接(connection)。有122304个连接,但是我们只需要学习156个参数,主要是通过权值共享实现的。

3、S2层-池化层(下采样层)

输入:28*28

采样区域:2*2

采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果通过sigmoid

采样种类:6

输出featureMap大小:14*14(28/2)

神经元数量:14*14*6

连接数:(2*2+1)*6*14*14

S2中每个特征图的大小是C1中特征图大小的1/4。

详细说明:第一次卷积之后紧接着就是池化运算,使用 2*2核 进行池化,于是得到了S2,6个14*14的 特征图(28/2=14)。S2这个pooling层是对C1中的2*2区域内的像素求和乘以一个权值系数再加上一个偏置,然后将这个结果再做一次映射。同时有5x14x14x6=5880个连接。

4、C3层-卷积层

输入:S2中所有6个或者几个特征map组合

卷积核大小:5*5

卷积核种类:16

输出featureMap大小:10*10      (14-5+1)=10

C3中的每个特征map是连接到S2中的所有6个或者几个特征map的,表示本层的特征map是上一层提取到的特征map的不同组合

存在的一个方式是:C3的前6个特征图以S2中3个相邻的特征图子集为输入。接下来6个特征图以S2中4个相邻特征图子集为输入。然后的3个以不相邻的4个特征图子集为输入。最后一个将S2中所有特征图为输入。

则:可训练参数:6*(3*5*5+1)+6*(4*5*5+1)+3*(4*5*5+1)+1*(6*5*5+1)=1516

连接数:10*10*1516=151600

5、S4层-池化层(下采样层)

输入:10*10

采样区域:2*2

采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果通过sigmoid

采样种类:16

输出featureMap大小:5*5(10/2)

神经元数量:5*5*16=400

连接数:16*(2*2+1)*5*5=2000

S4中每个特征图的大小是C3中特征图大小的1/4

详细说明:S4是pooling层,窗口大小仍然是2*2,共计16个feature map,C3层的16个10x10的图分别进行以2x2为单位的池化得到16个5x5的特征图。有5x5x5x16=2000个连接。连接的方式与S2层类似。

目录

1.LeNet介绍

2.LeNet网络结构

1、INPUT层-输入层

2、C1层-卷积层

3、S2层-池化层(下采样层)

4、C3层-卷积层

5、S4层-池化层(下采样层)

7、F6层-全连接层

8、Output层-全连接层

3.LeNet网络数据导入


输入:S4层的全部16个单元特征map(与s4全相连)

卷积核大小:5*5

卷积核种类:120

输出featureMap大小:1*1(5-5+1)

可训练参数/连接:120*(16*5*5+1)=48120

详细说明:C5层是一个卷积层。由于S4层的16个图的大小为5x5,与卷积核的大小相同,所以卷积后形成的图的大小为1x1。这里形成120个卷积结果。每个都与上一层的16个图相连。所以共有(5x5x16+1)x120 = 48120个参数,同样有48120个连接。C5层的网络结构如下:

网络解析(一):LeNet-5详解

7、F6层-全连接层

输入:c5 120维向量

计算方式:计算输入向量和权重向量之间的点积,再加上一个偏置,结果通过sigmoid函数输出。

可训练参数:84*(120+1)=10164

详细说明:6层是全连接层。F6层有84个节点,对应于一个7x12的比特图,-1表示白色,1表示黑色,这样每个符号的比特图的黑白色就对应于一个编码。该层的训练参数和连接数是(120 + 1)x84=10164。

F6层的连接方式如下:

网络解析(一):LeNet-5详解

8、Output层-全连接层

Output层也是全连接层,共有10个节点,分别代表数字0到9,且如果节点i的值为0,则网络识别的结果是数字i。采用的是径向基函数(RBF)的网络连接方式。

3.LeNet网络数据导入

数据的导入分为两步,分别是数据的加载和导入,在程序里通过两行代码实现

1.数据的加载

train_dataset = datasets.MNIST(root = './mnist', train = True,
                               transform = transforms.ToTensor(), download = False)
test_dataset = datasets.MNIST(root = './mnist', train = False,
                               transform = transforms.ToTensor(), download = False)

用dataset.MNIST来加载数据

root表示存放在当前目录下'data'文件夹中

train=True表示导入的是训练数据;train=False表示导入的是测试数据。

transform表示对每个数据进行的变化,这里是将其变为Tensor。Tensor是pytorch中存储数据的主要格式,类似于numpy,两者可相互转换。

dowload表示是否下载数据

1.从网络上下载

当dowload=Ture时,系统会从网上下载数据.不要求本地有数据集,该方法简单但是下载数据需要时间

2.本地加载

当dowload=Flase时,系统会从root里读取数据,需要注意的是,要想成功导入数据,需要将文件夹变成下面的格式:

2.数据的导入

train_loader = DataLoader(dataset = train_dataset, batch_size = 100, shuffle = True)
test_loader = DataLoader(dataset = test_dataset, batch_size= 100, shuffle = True)

使用DataLoader加载数据集。

dataset表示加载的数据集。

batch_size表示将多少个数据划分为一个batch,也就是一次性喂给模型多少个数据。

shuffle表示是否打乱数据顺序。

4.LeNet网络结构在pytorch下的实现

 把整体结构分成3层layers和两个fc

class LeNet5(nn.Module):
    def __init__(self):
        super(LeNet5, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(1, 6, 5, 1, 0),
            nn.ReLU(),
            nn.MaxPool2d(2,2))
        self.layer2 = nn.Sequential(
            nn.Conv2d(6, 16, 5, 1, 0),
            nn.ReLU(),
            nn.MaxPool2d(2,2))
        self.layer3 = nn.Sequential(
            nn.Conv2d(16, 120, 4, 1, 0),
            nn.ReLU())
        self.fc1 = nn.Linear(120,84)
        self.fc2 = nn.Linear(84,10)


    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = self.layer3(out)
        out = out.view(-1, 120)
        out = self.fc1(out)
        out = self.fc2(out)

        return out

 每一个layers里面有一个卷积,一个激活函数,一个池化

卷积第一个数字代表输入通道数,第二个数字代表输出通道数,第三个数字代表卷积核大小,第四个数据代表步长,第五个数据代表是否有padding

激活函数用的是ReLU激活函数

池化第一个数字代表2*2的卷积核,第二个数字代表步长为2

layer1:(32*32*1)-->(28*28*6)-->(14*14*6)

layer2:(14*14*6)-->(10*10*16)-->(5*5*16)

layer3:(5*5*16)-->120        按理来说应该用5*5的卷积核,但是程序无法运行,用4*4的卷积核就能运行

fc1:120-->84

fc2:84-->10

在进行前向传播的时候,两个全连接层前面有一个out = out.view(-1,120),目的是统一维度,

5.定义参数

device = torch.device('cuda')
model = LeNet5().to(device)
cost = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters())

 使用cuda进行训练,loss定义为交叉熵,使用Adam方法进行优化

6.训练部分

if __name__ == "__main__":
    epochs = 5
    for epoch in range(epochs):
        sum_loss = 0.0
        train_correct = 0
        for data in train_loader:
            inputs, lables = data
            inputs, lables = Variable(inputs).cuda(), Variable(lables).cuda()
            optimizer.zero_grad()
            outputs = model(inputs)
            loss = cost(outputs, lables)
            loss.backward()
            optimizer.step()

            _, id = torch.max(outputs.data, 1)
            sum_loss += loss.data
            train_correct += torch.sum(id == lables.data)

        print('[%d,%d] loss:%.03f' % (epoch + 1, epochs, sum_loss / len(train_loader)))
        print('         correct:%.03f%%' % (100 * train_correct / len(train_dataset)))

训练了5次,每次计算loss和准确度。

zero_grad()将上一个batch的梯度清零,以免梯度累加造成错误。

利用backward()进行反向传播计算梯度,optimizer.step()进行梯度下降。

torch.max(a,b)对a中的固定第b维的情况下,计算最大值,返回最大值及其索引。这里是固定outputs的列,对行求最大值。outputs返回的值可以看作是归属每个类的概率,取最大概率作为最终结果。

最后累加loss并计算准确度。

7.测试部分

model.eval()
test_correct = 0
for data in test_loader:
    inputs, lables =data
    inputs, lables =Variable(inputs).cuda(), Variable(lables).cuda()
    outputs = model(inputs)
    _, id = torch.max(outputs.data, 1)
    test_correct += torch.sum(id == lables.data)
print("correct:%.3f%%" % (100 * test_correct / len(test_dataset)))

测试需要用到model的eval()模式,以免将测试数据也用于训练。

8.运行结果

目录

1.LeNet介绍

2.LeNet网络结构

1、INPUT层-输入层

2、C1层-卷积层

3、S2层-池化层(下采样层)

4、C3层-卷积层

5、S4层-池化层(下采样层)

7、F6层-全连接层

8、Output层-全连接层

3.LeNet网络数据导入

1.数据的加载

2.数据的导入

4.LeNet网络结构在pytorch下的实现

5.定义参数

6.训练部分

7.测试部分

8.运行结果


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值