神经网络---卷积神经网络CNN

news2025/1/21 4:45:23

一、从前馈神经网络到CNN

前馈神经网络(Feedforward Neural Networks)是最基础的神经网络模型,也被称为多层感知机(MLP)。

它由多个神经元组成,每个神经元与前一层的所有神经元相,形成一个“全连接”的结构。每个神经元会对其输入数据进行线性变换(通过权重矩阵),然后通过一个非线性函数(如ReLU或Sigmoid)进行激活。这就是前馈神经网络的基本操作。

然而前馈神经网络也会产生问题:如果加深网络层,全连接神经网络随着隐藏层和隐藏节点的增加,参数的增加量是十分巨大的。正是因为这些大量的参数,使得神经网络模型有着极强的学习能力,导致计算困难。

很大程度上,是CNN的基本组成部分与前馈神经网络有很紧密的关联,甚至可以说,CNN就是一种特殊的前馈神经网络。

这两者的主要区别在于,CNN在前馈神经网络的基础上加入了卷积层和池化层(下边会讲到),以便更好地处理图像等具有空间结构的数据。

CNN在前馈神经网络的基础上加入了卷积层和池化层

所谓深度学习,不就是层数比较多的神经网络嘛,那为什么不能使用一种几十层的前馈神经网络,而要设计一个所谓的卷积神经网络呢?接下来我们来学习卷积神经网络模型。

二、卷积神经网络(CNN)介绍

卷积神经网络(CNN)是一种高效的深度学习架构,用于图像和视频识别、分类等任务。CNN通过局部连接权重共享自动特征提取等特点减少模型复杂度并提高计算效率。它在商业领域有广泛应用,如图像识别、医学图像分析、人脸识别等。Python中的深度学习框架如TensorFlow、Keras等.

CNN的网络结构分为3部分:输入层,隐藏层与输出层CNN的输入层是直接输入二维图像信息,这一点与传统的神经网络输入层需要输入一维向量有所不同。

隐藏层由三种网络构成 —— 卷积层(包含激活函数),池化层,全连接层

      卷积层:主要作用是提取特征,使用滤波器(卷积核),通过设定步长、深度等参数,对输入进行不同层次的特征提取。滤波器中的参数可以通过反向传播算法进行学习。

      激活函数层:主要是将卷积层的输出做一个非线性映射。常见的激活函数包括sigmoid,tanh,Relu等

      池化层:对卷积层提取的特征进行降维,主要是用于参数量压缩。可以减轻过拟合情况。常见的有平均池化和最大池化,不包含需要学习的参数。

     全连接层:主要是指两层网络,所有神经元之间都有权重连接。常见用于网络的最后一层,用于计算类别得分。

     输出层:输出层位于全连接层之后,对从全连接层得到的特征进行分类输出。

1、卷积层

卷积本质来说就是通过卷积核滑动遍历一幅图像像素矩阵,其权重w与对应位置像素相乘再相加的操作这里就涉及到几个概念:卷积核、步长、填充。

举个例子说明:比如有一张猫的图像,这里猫眼睛、猫脚、猫尾巴之间的距离是很大的,看猫眼睛的时候并不会影响到猫尾巴,所以图像具有局部相关性,在特征提取的时候专门设计找猫眼睛的卷积核在这个图像中找猫眼睛,专门找猫脚的卷积核来找猫脚,专门找猫尾巴的卷积核来找猫尾巴。

 (1)卷积核(Kernel) 

卷积核也称作滤波器,是用来滑动的窗口,卷积核尺寸通常为3×3×c,3×3是卷积核的大小,c是卷积核的通道数。注意,这里的c和这层的输出的通道是一样的,比如224×224×3的图像,用3×3×c的卷积,那么这里的c就是3。卷积核的每个小方格上都有一个权重w,这些权重是可学习参数,训练就是要找到最优的参数.

接下来我们以灰度图像为例(通道c=1):

左边矩阵容易被理解为一张图片,中间的这个被理解为卷积核,右边的图片我们可以理解为另一张图片。

第一步计算:

第二步计算:

第一行计算完成:

接下来为了得到下一行的元素,现在把蓝色块下移:

最后我们得到一个卷积计算结果为:

下图展示了使用两个三通道滤波器从三通道(RGB)图像中生成两个卷积输出的详细过程。

以上就是三维卷积计算方法。这里面体现了局部连接权值共享:每层神经元只和上一层部分神经元相连(卷积计算规则),且filter的权值对于上一层所有神经元都是一样的。对于包含两个3*3*3的fitler的卷积层来说,其参数数量仅有(3*3*3+1)*2=56个,且参数数量与上一层神经元个数无关。与全连接神经网络相比,其参数数量大大减少了。

2、步长

步长(stride)是卷积操作中的一个重要参数,它决定了卷积核在输入数据上移动的间隔。步长的选择直接影响卷积操作后输出特征图的大小和信息保留程度,是神经网络卷积操作的关键参数。步长的大小可以是正整数,通常为1、2、3等。

3、填充(padding)

在标准卷积中,存在两问题(1)每次卷积都会缩小图像的尺寸,图像会失去原来的形状;(2)在滑动时位于中间的像素会被重复滑动到,而位于边缘的像素就只被滑动一次,这意味着卷积过程丢掉了图像边缘的许多信息,因此,要解决这些问题,可以使用padding零填充,这样,在滑动时的卷积核可以允许原始边缘像素位于其中心,边缘有值的像素也能被计算到。如下图是padding=1的零填充。

图像填充操作

图像填充后卷积操作图

图像经过卷积得到的特征图大小是由卷积核大小、步长、padding共同决定的,其计算公式为 

2、池化层 (Pooling )

随着模型网络不断加深,卷积核越来越多,要训练的参数还是很多,而且直接拿卷积核提取的特征直接训练也容易出现过拟合的现象。CNN使用的另一个有效的工具被称为“池化(Pooling)”出现并解决了上面这些问题,为了有效地减少计算量,池化就是将输入图像进行缩小,减少像素信息,只保留重要信息;为了有效地解决过拟合问题,池化可以减少数据,但特征的统计属性仍能够描述图像,而由于降低了数据维度,可以有效地避免过拟合。

池化的定义:对不同位置区域提取出有代表性的特征(进行聚合统计,例如最大值、平均值等),这种聚合的操作就叫做 池化,池化的过程通常也被称为 特征映射 的过程(特征降维)。听起来很高深,其实简单地说就是下采样。

池化主要有两种, 最大值池化(Max Pooling)和 平均值池化(Average pooling),最大池化是对局部窗口的值取最大,平均池化是对局部窗口的值取平均。

详细的池化过如下:

池化核的大小:3×3

池化步长:1

池化类型 : 最大值池化(Max Pooling)

池化层的主要作用就是对非线性激活函数后的结果进行降采样,以减少参数的数量,避免过拟合,并提高模型的处理速度。

3、Flatten层&全连接层(Full Connected Layer)

Flatten:将最后的二维特征图打平成一维。

全连接层:对提取的特征进行非线性组合以得到输出。

到这一步,其实我们的一个完整的“卷积部分”就算完成了,如果想要叠加层数,一般也是叠加“Conv-MaxPooing",通过不断的设计卷积核的尺寸,数量,提取更多的特征,最后识别不同类别的物体。做完Max Pooling后,我们就会把这些数据“拍平”,丢到Flatten层,然后把Flatten层的output放到full connected Layer里,采用softmax对其进行分类。

一个完整的CNN结构

4、CNN网络的实战

import torch
import torch.nn as nn
from torchvision import transforms
from torchvision import datasets #torchvision计算机视觉库
from torch.utils.data import DataLoader
import torch.nn.functional as f   #使用functional中的ReLu激活函数
import torch.optim as optim
import matplotlib.pyplot as plt

# 准备数据集
batch_size = 64
#神经网络希望输入的数值较小,最好在0-1之间,所以需要先将原始图像(0-255的灰度值)转化为图像张量(值为0-1)
#仅有灰度值->单通道   RGB -> 三通道 读入的图像张量一般为W*H*C (宽、高、通道数) 在pytorch中要转化为C*W*H
transform = transforms.Compose([
     #将数据转化为图像张量
    transforms.ToTensor(),
    # 进行归一化处理,切换到0-1分布 (均值, 标准差)
    transforms.Normalize(mean=[0.1307,],std=[0.3081,])
])
train_dataset = datasets.MNIST(root="../mnist_data/",train=True,transform=transform,download=True)
test_dataset = datasets.MNIST(root="../mnist_data/",train=False,transform=transform,download=True)
"""
for step,(b_x,b_y) in enumerate (train_dataset):
    if step>0:
        break
batch_x=b_x.squeeze(1).numpy();#将思维张量移除第一维度,并转化为numpy数组
batch_y=b_y.numpy()
class_label=train_dataset.classes;
print(class_label.classes)
"""


#将自定义的dataset根据batch size的大小、是否shuffle等选项封装成一个batch size大小的tensor,后续就只需要在包装成variable即可作为模型的输入进行训练。
train_dataloader = DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True)
test_dataloader = DataLoader(dataset=test_dataset,batch_size=batch_size,shuffle=True)

# 网络模型
class Model(nn.Module):
    #构造函数,用于初始化对象的属性
    def __init__(self):
        super(Model, self).__init__()
        # 两个卷积层
        self.conv1 = nn.Conv2d(1,10,kernel_size=5) #1为in_channels 10为out_channels,卷积核大小是5X5的
        self.conv2 = nn.Conv2d(10,20,kernel_size=5)
        # 池化层
        self.pooling = nn.MaxPool2d(2)#2为最大池化窗口的大小
        # 全连接层 320 = 20 * 4 * 4
        self.fc = nn.Linear(320,10)

    def forward(self,x):
        # 先从x数据维度中得到batch_size
        batch_size = x.size(0)
        # 卷积层->池化层->激活函数
        x = f.relu(self.pooling(self.conv1(x)))
        x = f.relu(self.pooling(self.conv2(x)))
        x = x.view(batch_size, -1)  # 将数据展开,为输入全连接层做准备
        x = self.fc(x)
        return x
        # x = f.relu(self.pooling(self.conv1(x)))
        # x = f.relu(self.pooling(self.conv2(x)))
        # x = x.view(x.size(0), -1)
        # x = self.fc(x)
        # return x

model = Model()
#在这里加入两行代码,将数据送入GPU中计算!!!
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device) #将模型的所有内容放入cuda中
# 优化器和损失函数
criterion = nn.CrossEntropyLoss()
#神经网络已经逐渐变大,需要设置冲量momentum=0.5
optimizer = optim.SGD(model.parameters(),lr = 0.01,momentum=0.5)

# 训练
epoch_list = []
def train(epoch):
    running_loss = 0.0
    epoch_list.append(epoch+1)
    # for epoch in range(10):
    for i, data in enumerate(train_dataloader, 0):
        input, target = data
        input, target = input.to(device),target.to(device)
        y_pred = model(input)   #前向传播
        loss = criterion(y_pred, target)  #计算损失
        # print(i+1,epoch+1,loss.item())
        optimizer.zero_grad()
        loss.backward() #反向传播,计算梯度
        optimizer.step() #更新权重

        running_loss += loss.item()
        if i % 300 == 299:
            print("{} {} loss:{:.3f}".format(epoch + 1, i + 1, running_loss / 300))
            running_loss = 0.0
# 测试
accuracy_list = []
def test():
    total = 0
    correct = 0
    #表明当前计算不需要反向传播,使用之后,强制后边的内容不进行计算图的构建
    with torch.no_grad():
        for i,data in enumerate(test_dataloader,0):
            input,target = data
            input, target = input.to(device), target.to(device)
            y_pred = model(input)
            predicted = torch.argmax(y_pred.data,dim=1)  #找打最大概率的类别
            total += target.size(0)
            correct += (predicted==target).sum().item()
        accuracy = correct/total
        accuracy_list.append(accuracy)
        print("Accuracy on test set:{:.2f} %".format(100*correct/total))

if __name__ == '__main__':
    for epoch in range(10):
        train(epoch)
        test()
#画图
plt.plot(epoch_list,accuracy_list)
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.grid()
plt.show()

如果大家对神经网络知识感兴趣可以关注我的微信公众号,里面会分享一些知识干货。

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

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

相关文章

【C语言】基于C语言实现的贪吃蛇游戏

【C语言】基于C语言实现的贪吃蛇游戏 🔥个人主页:大白的编程日记 🔥专栏:C语言学习之路 文章目录 【C语言】基于C语言实现的贪吃蛇游戏前言一.最终实现效果一.Win32 API介绍1.1Win32 API1.2控制台程序1.3控制台屏幕上的坐标COORD…

【kubernetes】探索k8s集群的存储卷、pvc和pv

目录 一、emptyDir存储卷 1.1 特点 1.2 用途 1.3部署 二、hostPath存储卷 2.1部署 2.1.1在 node01 节点上创建挂载目录 2.1.2在 node02 节点上创建挂载目录 2.1.3创建 Pod 资源 2.1.4访问测试 2.2 特点 2.3 用途 三、nfs共享存储卷 3.1特点 3.2用途 3.3部署 …

放开了去的 ulimit

放开了去的 ulimit 放开了去的 ulimitulimit简介临时修改打开文件数目永久修改系统总打开句柄限制更多信息 放开了去的 ulimit ulimit简介 对于高并发或者频繁读写文件的应用程序而言,有时可能需要修改系统能够打开的最多文件句柄数,否则就可能会出现t…

【网络原理】HTTP|认识请求“报头“|Host|Content-Length|Content-Type|UA|Referer|Cookie

目录 认识请求"报头"(header) Host Content-Length Content-Type User-Agent(简称UA) Referer 💡Cookie(最重要的一个header,开发&面试高频问题) 1.Cookie是啥? 2.Cookie怎么存的? …

系统架构设计师【第8章】: 系统质量属性与架构评估 (核心总结)

文章目录 8.1 软件系统质量属性8.1.1 质量属性概念8.1.2 面向架构评估的质量属性8.1.3 质量属性场景描述 8.2 系统架构评估8.2.1 系统架构评估中的重要概念8.2.2 系统架构评估方法 8.3 ATAM方法架构评估实践8.3.1 阶段1—演示(Presentation)8.3…

卷积网络迁移学习:实现思想与TensorFlow实践

摘要:迁移学习是一种利用已有知识来改善新任务学习性能的方法。 在深度学习中,迁移学习通过迁移卷积网络(CNN)的预训练权重,实现了在新领域或任务上的高效学习。 下面我将详细介绍迁移学习的概念、实现思想&#xff0c…

SpringMVC响应数据 View

1.如何封装数据返回页面 使用ModelAndView: ModelAndView modelAndView new ModelAndView() modelAndView.addObject() 方法封装数据 使用Controller中内置Model对象 model: model.addAttribute("name","zz"); 2.跳转的方式…

el-date-picker的使用,及解决切换type时面板样式错乱问题

这里选择器的类型可以选择日月年和时间范围&#xff0c;根据类型不同&#xff0c;el-date-picker的面板也展示不同&#xff0c;但是会出现el-date-picker错位&#xff0c;或者面板位置和层级等问题。 源代码&#xff1a; <el-selectv-model"dateType"placeholder&…

【PTA】7-4 朋友圈(C++ * 并查集思想)代码实现 一点反思

题目如下&#xff1a; AC代码如下&#xff08;参考PTA 7-2 朋友圈&#xff08;25 分&#xff09;_处理微信消息pta-CSDN博客&#xff09; #include<bits/stdc.h> using namespace std; #define sz 30005 typedef struct node{int rk, fa; }Node; Node tree[sz]; void In…

HTTPS 原理技术

HTTPS原理技术 背景简介原理总结 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的日子。本文内容并非完全原创&am…

Ubuntu安装GCC编译器

GCC编译器安装 GCC编译器安装切换软件源(换成国内的服务器)1 、创建一个文本文档并命名为“sources.list”2 、复制软件源列表清华源:阿里源:3 、把修改之后的.list 文件覆盖原有的文件4 、更新软件列表5 、安装6 、检查是否安装成功7、GCC 编译器:GCC编译器安装 这里演示…

二维数组传参时不用二级指针接收

先放结论&#xff1a; 1. 二维数组数组名指向的类型是 int [x] 类型&#xff0c;int** 指针指向类型是 int* &#xff0c;如果用二级指针接收会导致访问错误&#xff0c;因为 int [x] 类型和 int* 类型不同。 2. 指向什么类型的指针1就按照该类型的字节数1移动。 最近在学…

高并发项目-分布式Session解决方案

分布式Session解决方案 1.保存Session&#xff0c;进入商品列表页面 1.保存Session 1.编写工具类 1.MD5Util.java package com.sxs.seckill.utils;import org.apache.commons.codec.digest.DigestUtils;/*** Description: MD5加密工具类** Author sun* Create 2024/5/5 14…

uni-app实现页面通信EventChannel

uni-app实现页面通信EventChannel 之前使用了EventBus的方法实现不同页面组件之间的一个通信&#xff0c;在uni-app中&#xff0c;我们也可以使用uni-app API —— uni.navigateTo来实现页面间的通信。注&#xff1a;2.8.9 支持页面间事件通信通道。 1. 向被打开页面传送数据…

【Linux】操作系统之冯诺依曼体系

&#x1f389;博主首页&#xff1a; 有趣的中国人 &#x1f389;专栏首页&#xff1a; Linux &#x1f389;其它专栏&#xff1a; C初阶 | C进阶 | 初阶数据结构 小伙伴们大家好&#xff0c;本片文章将会讲解 操作系统中 冯诺依曼体系 的相关内容。 如果看到最后您觉得这篇文…

File(文件)

File对象表示一个路径&#xff0c;可以是文件的路径&#xff0c;也可以是文件夹的路径。 这个路径可以存在&#xff0c;也允许不存在。 创建File对象的方法 public class test {public static void main(String [] args) {//根据字符串创建文件String str"C:\\Users\\PC…

每日一题——力扣141. 环形链表(举一反三+思想解读+逐步优化)

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 专业点评 时间复杂度分析 空间复杂度分析 总结 我要更强 方法2&#x…

cdo | 常用命令

整理一下平时经常会使用的cdo命令 如何来更改netcdf数据中的变量名呢&#xff1f; 假设我现在有一个sst月平均数据,希望将里面的变量名称sst修改为sst_new netcdf oisst_monthly { dimensions:lat 180 ;lon 360 ;time UNLIMITED ; // (476 currently)nbnds 2 ; variable…

V90 PN总线伺服通过FB285速度控制实现正弦位置轨迹运动(解析法和数值法对比测试)

V90总线伺服相关内容请参考专栏系列文章,这里不在详述 1、V90伺服PN总线速度随动控制 V90伺服PN总线速度随动控制(手摇轮功能)_手摇轮可以接总线plc吗?-CSDN博客文章浏览阅读632次。V90PN总线控制相关内容,请参考下面文章链接:博途1200/1500PLC V90 PN通信控制 (FB284功能…

【html】用html模拟微信布局

您做的这个模拟微信布局的作品很不错,使用了Flexbox布局来实现元素的灵活排列。以下是关于您代码的一些分析和建议: 效果图: 代码分析: 全局样式重置: 您使用了* { margin: 0; padding: 0; }来重置所有元素的边距。这是一个常见的做法,可以避免不同浏览器默认样式的差…