简易机器学习笔记(八)关于经典的图像分类问题-常见经典神经网络LeNet

news2024/11/26 12:43:27

前言

图像分类是根据图像的语义信息对不同类别图像进行区分,是计算机视觉的核心,是物体检测、图像分割、物体跟踪、行为分析、人脸识别等其他高层次视觉任务的基础。图像分类在许多领域都有着广泛的应用,如:安防领域的人脸识别和智能视频分析等,交通领域的交通场景识别,互联网领域基于内容的图像检索和相册自动归类,医学领域的图像识别等。

这里简单讲讲LeNet

我的推荐是可以看看这个视频,可视化的查看卷积神经网络是如何一层一层地抽稀获得特征,最后将所有的图像展开成一个一维的轴,再通过全连接神经网络预测得到一个最后的预测值。

手写数字识别 1.4 LeNet-5-哔哩哔哩

在这里插入图片描述

计算过程

前置知识:

  1. 步长 Stride & 加边 Padding

卷积后尺寸=(输入尺寸-卷积核大小+加边像素数)/步长 + 1

默认Padding = ‘valid’ (丢弃),strides = 1
在这里插入图片描述

正式计算

  1. 卷积层1:

第一层我们给定的图像时32 * 32,使用六个5 x 5的卷积核,步长为1

第一层中没有加边,那么卷积后的尺寸就是(32 - 5 + 0 )/1 + 1 =28,那么输出的图像就是 28*28的边长

在第一层中,由于我们使用了六个卷积核,我们得到的输出为:62828,可以理解为一个六层厚的图像

  1. 池化层1:

我们在池化层内在2x2的图像内选取了一个最大值或者平均值,也就是图片整体缩水到原先的二分之一,所以我们得到池化层的输出为 6 x 14 x 14

  1. 卷积层2:

还是按照公式,卷积后尺寸=(输入-卷积核+加边像素数)/步长 + 1,这个时候输入为6 x 14 x 14,这一次我们给定了16个卷积核,得到输出后的尺寸为(14 - 5 + 0)/1 + 1 = 10,得到输出为161010

关于这个16个卷积核是怎么来的,可以见图:

问了下组里的大佬,大佬说这个卷积核数目和层数很多是经验值,即你寻求更多或者更少的卷积核数目或者层数,实际效果不一定有经验值更好,反正都是离散值,就随便试试就行了。

其中:卷积输出尺寸nout:nin为输入原图尺寸大小;s是步长(一次移动几个像素);p补零圈数,

我们这里输入的值

  1. 池化层2

得到 输出后尺寸为16 * 5 * 5

  1. 全连接层1:

输入为16 * 5 * 5 ,有120个5*5卷积核,步长为1,输出尺寸为(5 - 5 + 0)/1 + 1 =1,这时候输出的就是一条直线的一维输出了

  1. 全连接层2:

输入为120,使用了84个神经元,

  1. 输出层

输入84,输出为10

比如我们如图所示,在代码中是这样的:

# 导入需要的包
import paddle
import numpy as np
from paddle.nn import Conv2D, MaxPool2D, Linear

## 组网
import paddle.nn.functional as F
from paddle.vision.transforms import ToTensor
from paddle.vision.datasets import MNIST
#定义LeNet网络结构

# 定义 LeNet 网络结构
class LeNet(paddle.nn.Layer):
    def __init__(self, num_classes=1):
        super(LeNet,self).__init__()
        #创建卷积层和池化层
        #创建第一个卷积层
        self.conv1 = Conv2D(in_channels=1,out_channels=6,kernel_size=5)
        self.max_pool1 = MaxPool2D(kernel_size=2,stride=2)
        #尺寸的逻辑:池化层未改变通道数,当前通道为6
        #创建第二个卷积层
        self.conv2 = Conv2D(in_channels=6,out_channels=16,kernel_size=5)
        self.max_pool2 = MaxPool2D(kernel_size=2,stride=2)
        #创建第三个卷积层
        self.conv3 = Conv2D(in_channels=16,out_channels=120,kernel_size=4)
        # 尺寸的逻辑:输入层将数据拉平[B,C,H,W] -> [B,C*H*W]
        # 输入size是[28,28],经过三次卷积和两次池化之后,C*H*W等于120
        self.fc1 = Linear(in_features=120, out_features=64)
        # 创建全连接层,第一个全连接层的输出神经元个数为64, 第二个全连接层输出神经元个数为分类标签的类别数
        self.fc2 = Linear(in_features=64, out_features=num_classes)

    # 网络的前向计算过程
    def forward(self, x):
        x = self.conv1(x)
        # 每个卷积层使用Sigmoid激活函数,后面跟着一个2x2的池化
        x = F.sigmoid(x)
        x = self.max_pool1(x)
        x = F.sigmoid(x)
        x = self.conv2(x)
        x = self.max_pool2(x)
        x = self.conv3(x)
        # 尺寸的逻辑:输入层将数据拉平[B,C,H,W] -> [B,C*H*W]
        x = paddle.reshape(x, [x.shape[0], -1])
        x = self.fc1(x)
        x = F.sigmoid(x)
        x = self.fc2(x)
        return x
# 飞桨会根据实际图像数据的尺寸和卷积核参数自动推断中间层数据的W和H等,只需要用户表达通道数即可。
# 下面的程序使用随机数作为输入,查看经过LeNet-5的每一层作用之后,输出数据的形状。

# 输入数据形状是 [N, 1, H, W]
# 这里用np.random创建一个随机数组作为输入数据
x = np.random.randn(*[3,1,28,28])
x = x.astype('float32')

# 创建LeNet类的实例,指定模型名称和分类的类别数目
model = LeNet(num_classes=10)

# 通过调用LeNet从基类继承的sublayers()函数,
# 查看LeNet中所包含的子层
print(model.sublayers())
x = paddle.to_tensor(x)

for item in model.sublayers():
    #item是LeNet类中的一个子层
    #查看经过子层之后的输出数据形状
    try:
        x = item(x)
    except:
        x = paddle.reshape(x, [x.shape[0], -1])
        x = item(x)
    if len(item.parameters())==2:
        # 查看卷积和全连接层的数据和参数的形状,
        # 其中item.parameters()[0]是权重参数w,item.parameters()[1]是偏置参数b
        print(item.full_name(), x.shape, item.parameters()[0].shape, item.parameters()[1].shape)
    else:
        # 池化层没有参数
        print(item.full_name(), x.shape)

# 设置迭代轮数
EPOCH_NUM = 5
#定义训练过程 
def train(model,opt,train_loader,valid_loader):
    print("start training ... ")
    model.train()
    for epoch in range(EPOCH_NUM):
        for batch_id, data in enumerate(train_loader()):
            img = data[0]
            label = data[1] 
            #计算模型输出
            # 计算模型输出
            logits = model(img)
            # 计算损失函数
            loss_func = paddle.nn.CrossEntropyLoss(reduction='none')
            loss = loss_func(logits, label)
            avg_loss = paddle.mean(loss)

            if batch_id % 2000 == 0:
                print("epoch: {}, batch_id: {}, loss is: {:.4f}".format(epoch, batch_id, float(avg_loss.numpy())))

            #反向传播
            avg_loss.backward()
            opt.step()
            opt.clear_grad()

        model.eval()
        accuracies = []
        losses = []

        for batch_id, data in enumerate(valid_loader()):
            img = data[0]
            label = data[1]
            # 计算模型输出
            logits = model(img)
            pred = F.softmax(logits)

            # 计算损失函数
            loss_func = paddle.nn.CrossEntropyLoss(reduction='none')
            loss = loss_func(logits, label)
            acc = paddle.metric.accuracy(pred, label)
            accuracies.append(acc.numpy())
            losses.append(loss.numpy())
        print("[validation] accuracy/loss: {:.4f}/{:.4f}".format(np.mean(accuracies), np.mean(losses)))
        model.train()
    # 保存模型参数
    paddle.save(model.state_dict(), 'mnist.pdparams')    

# 创建模型
model = LeNet(num_classes=10)
# 设置迭代轮数
EPOCH_NUM = 5
# 设置优化器为Momentum,学习率为0.001
opt = paddle.optimizer.Momentum(learning_rate=0.001, momentum=0.9, parameters=model.parameters())
# 定义数据读取器
train_loader = paddle.io.DataLoader(MNIST(mode='train', transform=ToTensor()), batch_size=10, shuffle=True)
valid_loader = paddle.io.DataLoader(MNIST(mode='test', transform=ToTensor()), batch_size=10)
# 启动训练过程
train(model, opt, train_loader, valid_loader)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1354550.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】二叉树的创建和遍历:前序遍历,中序遍历,后序遍历,层次遍历

目录 一、二叉树的定义 1、二叉树的定义 2、二叉树的五种形态 二叉树的子树 : 3、满二叉树与完全二叉树 4、二叉树的性质 5、二叉树的存储结构 1、顺序存储 ​编辑 2、链式存储 二、二叉树的遍历 按照前序序列构建二叉树 1、前 (先) 序遍历(Preorder …

没有Kubernetes也可以玩转Dapr?

一、NameResolution组件 虽然Dapr提供了一系列的编程模型,比如服务调用、发布订阅和Actor模型等,被广泛应用的应该还是服务调用。我们知道微服务环境下的服务调用需要解决服务注册与发现、负载均衡、弹性伸缩等问题,其实Dapr在这方面什么都没…

Golang拼接字符串性能对比

g o l a n g golang golang的 s t r i n g string string类型是不可修改的,对于拼接字符串来说,本质上还是创建一个新的对象将数据放进去。主要有以下几种拼接方式 拼接方式介绍 1.使用 s t r i n g string string自带的运算符 ans ans s2. 使用…

STM32 基础知识(探索者开发板)--135讲 ADC转换

ADC定义: ADC即模拟数字转换器,英文详称 Analog-to-digital converter,可以将外部的模拟信号转换 ADC数模转换中一些常用函数: 1. HAL_ADC_Init 函数 HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef *hadc); 初始化ADC 形参&…

网络连通性批量检测工具

一、背景介绍 企业网络安全防护中,都会要求配置物理网络防火墙以及主机防火墙,加强对网络安全的防护。云改数转之际,多系统上云过程中都会申请开通大量各类网络配置,针对这些复杂且庞大的网络策略开通配置,那么在网络配…

【12】ES6:模块化

一、JavaScript 模块化 JavaScript 模块化是一种组织和管理 JavaScript 代码的方法,它将代码分割为独立的模块,每个模块都有自己的作用域,并且可以导出和导入功能。模块化可以提高代码的可维护性、可重用性和可扩展性。 在JavaScript中&…

AIGC时代-GPT-4和DALL·E 3的结合

在当今这个快速发展的数字时代,人工智能(AI)已经成为了我们生活中不可或缺的一部分。从简单的自动化任务到复杂的决策制定,AI的应用范围日益扩大。而在这个广阔的领域中,有两个特别引人注目的名字:GPT-4和D…

2020年认证杯SPSSPRO杯数学建模A题(第二阶段)听音辨位全过程文档及程序

2020年认证杯SPSSPRO杯数学建模 A题 听音辨位 原题再现: 把若干 (⩾ 1) 支同样型号的麦克风固定安装在一个刚性的枝形架子上 (架子下面带万向轮,在平地上可以被水平推动或旋转,但不会歪斜),这样的设备称为一个麦克风树。不同的麦…

STM32CubeMX RS485接口使用

一、基本知识 TTL(Transistor-Transistor Logic): 电平范围: 逻辑1对应于2.4V–5V,逻辑0对应于0V–0.5V。通信特点: 全双工。特点: 常见于单片机和微控制器的IO电平,USB转TTL模块通常…

stable diffusion 人物高级提示词(一)头部篇

一、女生发型 prompt描述推荐用法Long hair长发一定不要和 high ponytail 一同使用Short hair短发-Curly hair卷发-Straight hair直发-Ponytail马尾high ponytail 高马尾,一定不要和 long hair一起使用,会冲突Pigtails2条辫子-Braid辫子只写braid也会生…

算法通关村番外篇-数组实现队列

大家好我是苏麟 , 今天来用数组实现一下队列 . 数组实现队列 顺序存储结构存储的队列称为顺序队列,内部使用一个一维数组存储,用一个队头指针 front 指向队列头部节点(即使用int类型front来表示队头元素的下标),用一个队尾指针rear(有的地方…

HTTP 代理原理及实现(二)

在上篇《HTTP 代理原理及实现(一)》里,我介绍了 HTTP 代理的两种形式,并用 Node.js 实现了一个可用的普通 / 隧道代理。普通代理可以用来承载 HTTP 流量;隧道代理可以用来承载任何 TCP 流量,包括 HTTP 和 H…

【InnoDB数据存储结构】第2章节:InnoDB行格式

目录结构 之前整篇文章太长,阅读体验不好,将其拆分为几个子篇章。 本篇章讲解 InnoDB 行格式。 InnoDB 行格式 InnoDB 一行记录是如何存储的? 这个问题是本文的重点,也是面试中经常问到的问题,所以就引出了下文的 …

水面漂浮物监测识别摄像机

水面漂浮物监测识别摄像机是一种用于监测水体表面上漂浮物的高科技设备。它主要通过安装在水域周边的摄像头实时捕捉水面情况,利用图像识别技术自动识别和监测水面漂浮物。这种设备在环境保护、水域清洁和水质监测等方面具有广泛的应用价值。 水面漂浮物包括各类垃圾…

vc2017编译从github网站上下载的源码

以ZLmediakit为例 1.下载软件 cmakehttps://github.com/Kitware/CMake/releases/download/v3.20.5/cmake-3.20.5-windows-x86_64.zip Microsoft Visual Studio https://my.visualstudio.com/Downloads?qvisual%20studio%202017&wt.mc_ido~msft~vscom~older-downloads …

一文搞懂SiLM824x系列SiLM8243BBCL-DG 双通道死区可编程隔离驱动 主要特性与应用 让技术变得更有价值

SiLM824x系列SiLM8243BBCL-DG是一款具有不同配置的隔离双通道门极驱动器。SiLM8243BBCL-DG配置为高、低边驱动,SiLM8243BBCL-DG可提供4A的输出源电流和6A的灌电流能力,并且其驱动输出电压可以支持到33V。支持死区可编程,通过调整DT脚外部的电…

Ansible、Saltstack、Puppet自动化运维工具介绍

本文主要是分享介绍三款主流批量操控工具Ansible、Saltstack、Puppet主要对比区别,以及Ansible和saltstack的基础安装和使用示例,如果觉得本文对你有帮助,欢迎点赞、收藏、评论! There are many things that can not be broken&am…

LeetCode刷题---矩阵置零

解题思路: 本题要求原地置换元素 对矩阵进行第一轮遍历,使用第一行第一列来充当该行该列是否要置换为0的标记位,如果第一行或第一列本身就含有零元素,我们使用colZero和rowZero变量来对其标记。如果第i行第j列的那个元素为0&#…

互联网分布式应用之SpringDataJPA

SpringDataJPA Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Spring整合Hibernate 2…

Spring配置文件

一: Bean标签基本配置 1:用途 用于配置对象交由Spring来创建,默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。 2:基本属性(id) Bean实例在Spring容器中的唯一…