LeNet-5

2023-09-14 15:54:54

目录

一、知识点

二、代码

三、查看卷积层的feature map

1. 查看每层信息

​2. show_featureMap.py


背景:LeNet-5是一个经典的CNN,由Yann LeCun在1998年提出,旨在解决手写数字识别问题。

一、知识点

1. iter()+next()

iter():返回迭代器

next():使用next()来获取下一条数据

data = [1, 2, 3]
data_iter = iter(data)
print(next(data_iter))  # 1
print(next(data_iter))  # 2
print(next(data_iter))  # 3

2. enumerate

enumerate(sequence,[start=0]) 函数用于将一个可遍历的数据对象组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

start--下标起始位置的值。 

data = ['zs', 'ls', 'ww']
print(list(enumerate(data)))
# [(0, 'zs'), (1, 'ls'), (2, 'ww')]

3. torch.no_grad()

在该模块下,所有计算得出的tensor的requires_grad都自动设置为False。

当requires_grad设置为False时,在反向传播时就不会自动求导了,可以节约存储空间。

4. torch.max(input,dim)

input -- tensor类型

dim=0 -- 行比较

dim=1 -- 列比较

import torch

data = torch.Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
x = torch.max(data, dim=0)
print(x)
# values=tensor([7., 8., 9.]),
# indices=tensor([2, 2, 2])
x = torch.max(data, dim=1)
print(x)
# values=tensor([3., 6., 9.]),
# indices=tensor([2, 2, 2])

5. torch.eq:对两个张量Tensor进行逐个元素的比较,若相同位置的两个元素相同,则返回True;若不同,返回False。

注意:item返回一个数。

import torch

data1 = torch.tensor([1, 2, 3, 4, 5])
data2 = torch.tensor([2, 3, 3, 9, 5])
x = torch.eq(data1, data2)
print(x)  # tensor([False, False,  True, False,  True])
sum = torch.eq(data1, data2).sum()
print(sum)  # tensor(2)
sum_item = torch.eq(data1, data2).sum().item()
print(sum_item)  # 2

6. squeeze(input,dim)函数

squeeze(0):若第一维度值为1,则去除第一维度

squeeze(1):若第二维度值为2,则去除第二维度

squeeze(-1):去除最后维度值为1的维度

7. unsqueeze(input,dim)

增加大小为1的维度,即返回一个新的张量,对输入的指定位置插入维度 1且必须指明维度。

二、代码

model.py

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

class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 16, 5)  # output(16,28,28)
        self.pool1 = nn.MaxPool2d(2, 2)  # output(16,14,14)
        self.conv2 = nn.Conv2d(16, 32, 5)  # output(32,10,10)
        self.pool2 = nn.MaxPool2d(2, 2)  # output(32,5,5)
        self.fc1 = nn.Linear(32 * 5 * 5, 120)  # output:120
        self.fc2 = nn.Linear(120, 84)  # output:84
        self.fc3 = nn.Linear(84, 10)  # output:10

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = self.pool1(x)
        x = F.relu(self.conv2(x))
        x = self.pool2(x)
        x = x.view(-1, 32 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

train.py

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

from model import LeNet

def main():
    # preprocess data
    transform = transforms.Compose([
        # Converts a PIL Image or numpy.ndarray (H x W x C) in the range [0, 255] to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0]
        transforms.ToTensor(),
        # (mean[1],...,mean[n])`` and std: ``(std[1],..,std[n])
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    ])
    # 训练集 如果数据集已经下载了,则download=False
    train_data = torchvision.datasets.CIFAR10('./data', train=True, transform=transform, download=False)
    train_loader = torch.utils.data.DataLoader(train_data, batch_size=36, shuffle=True, num_workers=0)
    # 验证集
    val_data = torchvision.datasets.CIFAR10('./data', train=False, download=False, transform=transform)
    val_loader = torch.utils.data.DataLoader(val_data, batch_size=10000, shuffle=False, num_workers=0)

    # 返回迭代器
    val_data_iter = iter(val_loader)
    val_image, val_label = next(val_data_iter)

    net = LeNet()
    loss_function = nn.CrossEntropyLoss()
    optimizer = optim.Adam(net.parameters(), lr=0.001)

    # loop over the dataset multiple times
    for epoch in range(5):
        epoch_loss = 0
        for step, data in enumerate(train_loader, start=0):
            # get the inputs from train_loader;data is a list of[inputs,labels]
            inputs, labels = data
            # 在处理每一个batch时并不需要与其他batch的梯度混合起来累积计算,因此需要对每个batch调用一遍zero_grad()将参数梯度设置为0
            optimizer.zero_grad()
            # 1.forward
            outputs = net(inputs)
            # 2.loss
            loss = loss_function(outputs, labels)
            # 3.backpropagation
            loss.backward()
            # 4.update x by optimizer
            optimizer.step()

            # print statistics
            # 使用item()取出的元素值的精度更高
            epoch_loss += loss.item()
            # print every 500 mini-batches
            if step % 500 == 499:
                with torch.no_grad():
                    outputs = net(val_image)
                    predict_y = torch.max(outputs, dim=1)[1]  # [0]取每行最大值,[1]取每行最大值的索引
                    val_accuracy = torch.eq(predict_y, val_label).sum().item() / val_label.size(0)
                    print('[epoch:%d step:%5d] train_loss:%.3f test_accuracy:%.3f' % (
                        epoch + 1, step + 1, epoch_loss / 500, val_accuracy))
                    epoch_loss = 0
    print('Train finished!')

    sava_path = './model/LeNet.pth'
    torch.save(net.state_dict(), sava_path)


if __name__ == '__main__':
    main()

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)),
        transforms.ToTensor(),  # CHW格式
        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('./model/LeNet.pth'))

    image = Image.open('./predict/2.png')  # HWC格式
    image = transform(image)
    image = torch.unsqueeze(image, dim=0)  # 在第0维加一个维度 #[N,C,H,W] N:Batch批处理大小

    with torch.no_grad():
        outputs = net(image)
        predict = torch.max(outputs, dim=1)[1]
    print(classes[predict])


if __name__ == '__main__':
    main()

2.png

 

三、查看卷积层的feature map

1. 查看每层信息

    for i in net.children():
        print(i)

2. show_featureMap.py

import torch
import torch.nn as nn
from model import LeNet
import torchvision
import torchvision.transforms as transforms
from PIL import Image
import matplotlib.pyplot as plt

def main():
    transform = transforms.Compose([
        transforms.Resize((32, 32)),
        transforms.ToTensor(),  # CHW格式
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    ])

    image = Image.open('./predict/2.png')  # HWC格式
    image = transform(image)
    image = torch.unsqueeze(image, dim=0)  # 在第0维加一个维度 #[N,C,H,W] N:Batch批处理大小

    net = LeNet()
    net.load_state_dict(torch.load('./model/LeNet.pth'))
    conv_weights = []  # 模型权重
    conv_layers = []  # 模型卷积层
    counter = 0  # 模型里有多少个卷积层

    # 1.将卷积层以及对应权重放入列表中
    model_children = list(net.children())
    for i in range(len(model_children)):
        if type(model_children[i]) == nn.Conv2d:
            counter += 1
            conv_weights.append(model_children[i].weight)
            conv_layers.append(model_children[i])

    outputs = []
    names = []
    for layer in conv_layers[0:]:
        # 2.每个卷积层对image进行计算
        image = layer(image)
        outputs.append(image)
        names.append(str(layer))
    # 3.进行维度转换
    print(outputs[0].shape)  # torch.Size([1, 16, 28, 28]) 1-batch 16-channel 28-H 28-W
    print(outputs[0].squeeze(0).shape)  # torch.Size([16, 28, 28]) 去除第0维
    # 将16颜色通道的feature map加起来,变为一张28×28的feature map,sum将所有灰度图映射到一张
    print(torch.sum(outputs[0].squeeze(0), 0).shape)  # torch.Size([28, 28])

    processed_data = []
    for feature_map in outputs:
        feature_map = feature_map.squeeze(0)  # torch.Size([16, 28, 28])
        gray_scale = torch.sum(feature_map, 0)  # torch.Size([28, 28])
        # 取所有灰度图的平均值
        gray_scale = gray_scale / feature_map.shape[0]
        processed_data.append(gray_scale.data.numpy())

    # 4.可视化特征图
    figure = plt.figure()
    for i in range(len(processed_data)):
        x = figure.add_subplot(1, 2, i + 1)
        x.imshow(processed_data[i])
        x.set_title(names[i].split('(')[0])
    plt.show()


if __name__ == '__main__':
    main()

更多推荐

数据结构——排序算法——基数排序

基数排序有两种实现方式。本例属于最高位优先法,思路是从最高位开始,依次对基数进行排序。与之对应的是「最低位优先法」,思路是从最低位开始,依次对基数进行排序。基数排序可以分为以下三个步骤:1.找到数组中的最大值,确定最大数字的位数2.从最低位开始,对数组进行计数排序。计数排序是稳定排序,所以在每一位排序后,相同数值的元素

排序算法-快速排序

属性快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。.1.快速排序整体的综合性

设计模式:享元模式

目录组件代码实现源码中使用总结享元模式(FlyweightPattern)是一种结构型设计模式,它旨在通过共享对象来最大程度地减少内存使用和提高性能。享元模式通过共享细粒度的对象,以有效地支持大量细粒度的对象实例。在享元模式中,对象分为两种类型:内部状态(IntrinsicState)和外部状态(ExtrinsicSt

ArmSoM-W3之RK3588 Debian11详解

1.简介RK3588从入门到精通Debian是⼀种完全⾃由开放并⼴泛⽤于各种设备的Linux操作系统。Rockchip在官⽅Debian发⾏版的基础上构建和适配了相关硬件功能2.环境介绍硬件环境:ArmSoM-W3RK3588开发板软件版本:OS:ArmSoM-W3Debian113.Debian目录结构debian├

Ae 效果:CC Mr. Mercury

模拟/CCMr.MercurySimulation/CCMr.MercuryCCMr.Mercury(CC水银先生)主要用于创建类似水银等液态金属或油漆等的动态效果。CCMr.Mercury本质上模拟一个发射水银粒子的椭圆形发生器,基于源图像的像素创建自带动画的效果,范围限制在图层大小范围内。◆◆◆效果属性说明Radi

Git学习笔记9

Gitlab中的代码是要部署到生产服务器上。CI:Continuousintegration简称CI:是一种软件开发实践,即开发团队成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化构建(包括编译、发布、自动化测试)来验证,从而尽快地发现集成中的错误。构建:对代

怎样才能让百度搜索到自己的博客?--九五小庞

怎么把自己的博客推荐到百度、Google等主要搜索引擎?如果不把你的博客提交到各大搜索引擎中,它们一般是不会收录你的博客的,你可以先尝试一下看看能不能在百度搜到你的博客吧。如果搜不到的话说明你的博客还没有被百度收录,那么怎么才能被百度、google等各大搜索引擎收录你的博客呢?申请免费加入搜索引擎啦!一般百度在48小时

Vue的详细教程--基础语法【上】

🥳🥳WelcomeHuihui'sCodeWorld!!🥳🥳接下来看看由辉辉所写的关于Vue的相关操作吧目录🥳🥳WelcomeHuihui'sCodeWorld!!🥳🥳一.插值1.文本2.html3.属性&class绑定&style绑定4.表达式二.指令1.v-if&v-else&v-else-if2.

mySQL 安装

一、windows安装包下载mysql官网提供了两种安装方式,一个是zip安装,另一个是msi安装,这里简绍第一种安装方式,第二种简单,不再简绍官网下载,根据自己需要选择版本:MySQL::MySQLCommunityDownloads这里我选择的是5.7版本二、安装文件1.解压到非中文、非特殊字符路径下2.将bin目

【支持M1】MacDroid for Mac:Mac和Android安卓设备数据互通

Mac和Android组合始终存在的唯一问题是无法在这些设备之间足够快地传输数据,但是MacDroidformac填补了这一空白。MacDroidmac版是Macos上一款安卓手机数据传输助手,MacDroidmac下载支持Mac和Android设备之间传输照片,视频,音乐和文件夹。不需要特殊的电缆或复杂的解决方案,只

【QT开发(5)】0919-QT里面新增ui类,新增使用opencv读取图片的普通类,在ui类中显示图片

参考资料1、QtCreator快速入门_第三版__霍亚飞编著2、《Qt+OpenCV显示图片(Mat转QImage然后显示在QLabel上)》输出材料https://gitee.com/hiyanyx/qt5.14-cpp_-empty_-project/tree/508435b09ff1f794e650cba859b

热文推荐