大模型系列5--卷积神经网络

news2024/12/28 19:18:52

卷积神经网络

  • 1. 背景
  • 2. 架构
    • 2.1. 卷积
      • 2.1.1. 单卷积层(多Channel输出)
      • 2.2.2. 多层卷积(卷积堆叠)
      • 2.2.3. 卷积关键参数
      • 2.2.4. 卷积常用计算公式
    • 2.2. 池化层(pooling)
  • 3. 经典网络结构
    • 3.1. VGG-16
    • 3.2. ResNet
  • 4. 代码
    • 4.1. 数据构建和载入
    • 4.2. 网络结构定义
    • 4.3. 模型训练和验证
    • 4.4. 完整代码

1. 背景

在看大模型的一些内容中,为了更好的理解其实现,现对一些经典的网络模型进行学习。本文参考bilibili视频内容:https://www.bilibili.com/video/BV1zF411V7xu/,感谢博主

本文学习的卷积神经网络CNN,在视觉领域非常知名,但也不只用于视觉领域。相比于普通NN,CNN引入了卷积层和池化层两个概念

  • 卷积层:对图片的一块一块的小方格位置进行特征提取,通过不同权重的卷积核可以提出图形的各类特征
  • 池化层:在提取完特征后,考虑到特征数目多,可以将特征矩阵小方格内最大的权重拿出来,通过这种方式进行降采样。

本文使用的pytorch进行的代码实践,在涉及到具体CNN代码训练时,本文作者对 train,optimiser,loss.backward等逻辑并没有很好的认知,代码内部有些过于黑盒了,学起来心里面太虚。 于是决定在余下的一些时间中,详细看下基本NN的代码训练逻辑,和NN的一些理论能够结合起来,让作者对代码能够认识的更清楚一些

2. 架构

  • 包括输入层、卷积层、池化层、全连接层
    在这里插入图片描述
    如下图是一个7层卷积神经网络图
    在这里插入图片描述

2.1. 卷积

  • 下图对一个32323的图片,使用一个333的卷积核进行处理
  • 卷积操作是将卷积核在图片中游走,在游走到某个位置时,执行的操作是对应位置的元素进行相乘再相加(下图右边以3*3的核进行的卷积,只表达了两维的概念)
  • 注意:卷积核的第三个维度一定和输入特征的第三个维度相同
    在这里插入图片描述
  • 对于一个三维核,可将第三维展开,例如如下图一个图片的第三维代表RGB三种颜色值,使用一个333的卷积核进行卷积计算,可以展开成3个3*3的二维卷积
    在这里插入图片描述

2.1.1. 单卷积层(多Channel输出)

  • 对一个输入图片32323,每个卷积5*5的卷积核,会对应生成一个二维特征图,也叫 一个channel
  • 可以使用多个卷积核,生成多个二维图,即如下图右边多个平面,平面的数目即是输出channel的数目
    在这里插入图片描述

2.2.2. 多层卷积(卷积堆叠)

  • 实际应用中,不会只有一层卷积层,而是多层卷积堆叠而成
  • 如下图,第一层卷积使用 5 ∗ 5 ∗ 3 5*5*3 553,第二层卷积使用 5 ∗ 5 ∗ 6 5*5*6 556
  • 第一层卷积的输出是 28 ∗ 28 ∗ 6 28*28*6 28286,28和6是怎么来的?
    • 28来源于 32 − 5 + 1 32 - 5 + 1 325+1,其中5是卷积核的大小,且采用的卷积核滑动窗口为1
    • 6是特征图的个数,这表明使用6个553的卷积核
  • 第二层卷积的输出是 24 ∗ 24 ∗ 10 24*24*10 242410,24和10是怎么来的?
    • 24等于 28 − 5 + 1 28 -5 +1 285+1
    • 10是特征图的个数,这里使用的是 5 ∗ 5 ∗ 6 5*5*6 556的卷积核

在这里插入图片描述

2.2.3. 卷积关键参数

  • 滑动窗口步长:最常用是1,或者是2
  • 边缘填充:边缘填充的圈数,填充0(目的是为了让原有边缘更靠内,确保边缘计算公平性)
  • 卷积核大小:最常用是33,或者55
  • 卷积核个数:生成特征图的个数

2.2.4. 卷积常用计算公式

  • 一层卷积输出特征是多少?
    • 以其中一维的长度举例,它等于 输入长度 + 2 ∗ 边缘填充 − 核大小 滑动窗口步长 + 1 \frac{输入长度 + 2 * 边缘填充 - 核大小}{滑动窗口步长} + 1 滑动窗口步长输入长度+2边缘填充核大小+1
    • 以输入 32 ∗ 32 ∗ 3 32*32*3 32323图像为例,用 10 10 10 5 ∗ 5 ∗ 3 5*5*3 553的卷积核filter来指定步长为1,边界填充为2,则最终卷积输出特征为 32 ∗ 32 ∗ 10 32*32*10 323210,其长度计算为 32 + 2 ∗ 2 − 5 1 + 1 = 32 \frac{32 + 2*2 - 5}{1}+1=32 132+225+1=32,宽度计算和长度计算等同。
  • 一层卷积的参数有多少个?
    • 10 10 10 5 ∗ 5 ∗ 3 5*5*3 553的卷积核,每个卷积核包括 W = 5 ∗ 5 ∗ 3 W = 5*5*3 W=553以及额外的 b b b,则总参数个数为: 10 ∗ 5 ∗ 5 ∗ 3 + 10 = 760 10 * 5 * 5 * 3 + 10 = 760 10553+10=760

2.2. 池化层(pooling)

  • 池化是用来降采样的(选取最有作用的特征)
  • 一般是使用最大特征,即Max-Pooling
    在这里插入图片描述

3. 经典网络结构

3.1. VGG-16

  • 13个卷积层(2个 卷积(2)-池化 +3个 卷积(3)-池化)
  • 最后3个全连接层:FC-4096,FC-4096,FC-1000
    在这里插入图片描述

3.2. ResNet

  • 网络更深,不见得更好
  • 直通越过某些无用的层,可以更多层,至少不会比层数少的网络差
    在这里插入图片描述

4. 代码

从视频中,一字一句抄了一份代码,目前IDE的补全能力很强,基本上写几个字母就可以猜到后续要用什么,因此代码实际抄起来还挺快。

这份代码包含三个部分

  • 数据构建和载入
  • 网络结构定义
  • 网络训练和验证

4.1. 数据构建和载入

torchvision有datasets库可以自动从网上下载MNIST数据集,完全不需要任何数据准备的工作,傻瓜式写代码。数据集要和dataloader绑定在一起,具体dataloader的作用机制是如何的,可以参考大模型系列3-pytorch dataloader的原理。

4.2. 网络结构定义

利用前述知识,可以很容易构建一个三层CNN,它包括两个卷积层和一个全连接层,每个卷积后面接Relu和MaxPooling,经典网络有2卷1pooling,和三卷1pooling的。

  • conv1:第1层卷积
  • conv2:第2层卷积
  • out:全连接层

特别要注意的是卷积的各个参数的设定

  • in_channels:输入数据的第三维的大小
  • out_channels:输出的特征图的个数
  • kernel_size:卷积核第1和2维的大小
  • stripe:卷积的滑动窗口步长
  • padding:卷积边缘补充0的宽度,为2表明周围补充两圈
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(in_channels=1,out_channels=16,kernel_size=5,stride=1,padding=2),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2),
        ) #14*14*16
        self.conv2 = nn.Sequential(
            nn.Conv2d(in_channels=16,out_channels=32,kernel_size=5,stride=1,padding=2),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2),
        )#7*7*32
        self.out = nn.Linear(32*7*7,10)
    def forward(self,x):
        x=self.conv1(x)
        x=self.conv2(x)
        x=x.view(x.size(0),-1)
        output=self.out(x)
        return output

4.3. 模型训练和验证

训练阶段的代码很简单,基本上都是分成多轮epoch,每轮分batch遍历所有的数据,在每个batch中执行如下工作:训练,损失计算,优化器,反向传播

net.train()
output = net(data)
loss = criterion(output, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
  • 对这块代码做不到很强的认知,后续会从基本NN的逻辑出发,看看其实现的机制是什么,本文暂不展开,等分析完其逻辑之后,会将相关的链接贴在这里。
for epoch in range(num_epochs):
    train_rights=[]
    for batch_idx, (data, target) in enumerate(train_loader):
        net.train()
        output = net(data)
        loss = criterion(output, target)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        rights= accuracy(output, target)
        train_rights.append(rights)
        if batch_idx % 100 == 0:
            net.eval()
            val_rights=[]
            for (data,target) in test_loader:
                output = net(data)
                right = accuracy(output, target)
                val_rights.append(right)
            train_r = (sum([top[0] for top in train_rights]), sum([top[1] for top in train_rights]))
            val_r = (sum([top[0] for top in val_rights]), sum([top[1] for top in val_rights]))

            print('当前epoch: {}[{}/{}({:.0f}%)]\t损失:{:.6f}\t训练集准确率:{:.2f}%\t测试集正确率:{:.2f}%'.format(
                epoch,
                batch_idx * batch_size,
                len(train_loader.dataset),
                100.*batch_idx/len(train_loader),
                loss.data,
                100.*train_r[0]/train_r[1],
                100.*val_r[0]/val_r[1]))

4.4. 完整代码

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torchvision import datasets,transforms
import matplotlib.pyplot as plt
import numpy as np

#定义超参数
input_size=28 #图像的总尺寸28*28
num_classes=10 #标签的种类数
num_epochs=3 #训练的总循环周期
batch_size=64 #一个(批次)的大小,64张图片

#训练集
train_dataset = datasets.MNIST(root="./data", train=True, transform=transforms.ToTensor(), download=True)
# 测试集
test_dataset = datasets.MNIST(root="./data", train=False, transform=transforms.ToTensor(), download=True)

#构建batch数据
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)

class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(in_channels=1,out_channels=16,kernel_size=5,stride=1,padding=2),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2),
        ) #14*14*16
        self.conv2 = nn.Sequential(
            nn.Conv2d(in_channels=16,out_channels=32,kernel_size=5,stride=1,padding=2),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2),
        )#7*7*32
        self.out = nn.Linear(32*7*7,10)
    def forward(self,x):
        x=self.conv1(x)
        x=self.conv2(x)
        x=x.view(x.size(0),-1)
        output=self.out(x)
        return output
def accuracy(predictions, labels):
    pred = torch.max(predictions.data,1)[1]
    rights = pred.eq(labels.data).cpu().sum()
    return rights,len(labels)

net = CNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=0.001)

for epoch in range(num_epochs):
    train_rights=[]
    for batch_idx, (data, target) in enumerate(train_loader):
        net.train()
        output = net(data)
        loss = criterion(output, target)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        rights= accuracy(output, target)
        train_rights.append(rights)
        if batch_idx % 100 == 0:
            net.eval()
            val_rights=[]
            for (data,target) in test_loader:
                output = net(data)
                right = accuracy(output, target)
                val_rights.append(right)
            train_r = (sum([top[0] for top in train_rights]), sum([top[1] for top in train_rights]))
            val_r = (sum([top[0] for top in val_rights]), sum([top[1] for top in val_rights]))

            print('当前epoch: {}[{}/{}({:.0f}%)]\t损失:{:.6f}\t训练集准确率:{:.2f}%\t测试集正确率:{:.2f}%'.format(
                epoch,
                batch_idx * batch_size,
                len(train_loader.dataset),
                100.*batch_idx/len(train_loader),
                loss.data,
                100.*train_r[0]/train_r[1],
                100.*val_r[0]/val_r[1]))

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

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

相关文章

燃气安全无小事,一双专业劳保鞋让你步步安心!

燃气作为我们日常生活中不可或缺的能源之一,为我们的生活提供了极大便利,其安全性往往被忽视在忙碌的日常生活背后。然而,燃气事故一旦发生,后果往往不堪设想,轻则财产损失,重则危及生命。因此,…

【Linux】全志Tina配置AB区分区升级包

一、文件位置 V:\f1c100s\Evenurs\f1c100s\tina\target\allwinner\generic\configs\sw-subimgs-ab.cfg 二、文件内容 三、介绍 在第七行,可以设置产生的升级包是a区或是b区,使用ab区的名称来区分,ab区名称查询方法详见文章: …

angular入门基础教程(八)表单之双向绑定

绑定表单数据 为了让表单使用 Angular 的特性实现数据绑定,需要导入 FormsModule。 这个比 vue 要繁琐点,不复杂,但是比 react 的自己手动实现要方便,ng 帮我们实现了双向绑定 import { Component } from "angular/core&qu…

金蝶云星空历史库存信息批量计算生成

文章目录 金蝶云星空历史库存信息批量计算生成业务背景需求背景参考开发步骤创建单据《历史库存信息》界面表结构需要生成日期库存信息的日期范围存储为表创建日期表使用递归插入数据创建存储过程1,根据日期生成计算当日库存,生成《历史库存信息》创建存储过程2,根据日期范围…

Linux修炼之路之进程优先级,并行,环境变量

目录 一:进程优先级 二:并行并发 三:环境变量 接下来的日子会顺顺利利,万事胜意,生活明朗-----------林辞忧 一:进程优先级 1.基本概念 当使用ps -al指令时,就会显示用户所启动的所有进…

音视频入门基础:WAV专题(4)——FFmpeg源码中获取WAV文件音频压缩编码格式、采样频率、声道数量、采样位数、码率的实现

音视频入门基础:WAV专题系列文章: 音视频入门基础:WAV专题(1)——使用FFmpeg命令生成WAV音频文件 音视频入门基础:WAV专题(2)——WAV格式简介 音视频入门基础:WAV专题…

求职Leetcode题目(2)

1.柱状图中最大的矩形 据说这是2024年字节二面的题目,我感觉这道题跟接雨水有点类似,最重要的思路还是要找到什么时候能形成矩形的这么个情况,某个范围的矩形的高度,是由最短的柱形来决定的。 我们先整理一下,解决这道…

解决Firefox代理身份验证弹出窗口问题:C#和Selenium实战指南

引言 在使用Selenium和C#进行网页抓取时,遇到代理服务器的身份验证弹出窗口是一个常见的问题。这不仅会中断自动化流程,还会导致抓取任务失败。本文将提供一个实战指南,帮助开发者解决这个问题,并介绍如何在代码中设置代理IP、Us…

N32L406 移植MultiTimer教程 mdk5

MultiTimer 首先感谢开源作者 开源地址; github.com https://github.com/0x1abin/MultiTimer 简介 MultiTimer 是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的…

C++学习笔记之指针高阶

数组名 数组名字是数组的首元素地址。 一个指针变量保存了数组元素的地址。我们就称之为数组元素指针,及数组指针。 数组指针的本质是指针,指向数组中的某个元素的地址。 由于数组名可以代表数组收元素地址,数组元素是可以通过 数组名[下标] 的格式访问, 那么可以定义一…

红酒行业新动态:抢先了解未来趋势

在风起云涌的红酒市场中,每一次变革都如同飓风般席卷整个行业。今日,我们一同探讨红酒行业的新动态,特别是定制红酒领域的未来趋势。让我们以洒派红酒(Bold & Generous)为引,洞察行业前沿,预…

60、redis安装和部署

一、关系型数据库与非关系型数据库 1.1、关系型数据库 关系型数据库是一个结构化的数据库,创建在关系模型(二维表格模型)基础上一般面向于记录。SQL语句(标准数据查询语言)就是一种基于关系型数据库的语言&#xff0…

2024-07学习笔记

1.${}取值 在这些属性源中,命令行参数和JVM系统属性拥有最高的优先级,它们可以覆盖在Properties文件中定义的属性。而操作系统环境变量和Properties文件的优先级相对较低,但是Spring会根据配置的不同情况进行属性的合并和覆盖,最终…

QUARKUS初体验

1.什么是QUARKUS? Quarkus是 Red Hat为GraalVM 和 HotSpot 量身定制用程序。特点是启动超快,内存极低,并且在容器编排平台(如Kubernetes)中提供了近乎即时的向上扩展和高密度的内存利用率。并且基于GraalVM&#xff0…

【YashanDB知识库】如何远程连接、使用YashanDB?

问题现象 在各个项目实施中,我们经常遇到客户、开发人员需要连接和使用YashanDB但不知如何操作的问题,本文旨在介绍远程连接、使用YashanDB的几种方式。 问题的风险及影响 无风险 问题影响的版本 历史版本~23.2 问题发生原因 无 解决方法及规避方…

Pytorch基础:Tensor的连续性

相关阅读 Pytorch基础https://blog.csdn.net/weixin_45791458/category_12457644.html?spm1001.2014.3001.5482 在Pytorch中,一个连续的张量指的是张量中各数据元素在底层的存储顺序与其在张量中的位置一致。这意味着每一个元素的地址可以通过下面的线性映射公式来…

MySQL8--用户与权限管理

原文网址:MySQL8--用户与权限管理_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍MySQL8的用户与权限的管理,包括:用户的创建与删除、授权与撤销权限等。 为什么要管理用户与权限? 目的是保证数据库的安全性,只授…

TCP/IP协议——使用Socket套接字实现

目录 Socket 使用Socket实现TCP客户端和服务器的过程 使用Socket搭建TCP服务器 线程优化 向客户端发送消息 连接的断开 客户端主动断开 服务端主动断开 服务器完整的程序 使用Socket编写客户端程序连接TCP服务器 Socket Socket是一种网络通信协议,它允许…

不再担心数据丢失:用rsync打造你的自动化备份解决方案

在现代IT环境中,数据备份是一项至关重要的任务。无论是个人文件还是企业数据,都需要有可靠的备份机制来防止数据丢失。今天,我们将介绍一种高效的备份方案:使用rsync实现自动化备份目录。 什么是rsync? rsync 是一个开…

vscode+cmake+msvc+vcpkg的入门使用

一.环境安装 1.下载vscode并安装: Download Visual Studio Code - Mac, Linux, Windows 2.安装完成后,安装C和cmake 相关工具,如图。 3.vcpkg的下载和安装 克隆vcpkg的仓库到本地:https://github.com/microsoft/vcpkg.git,运行bo…