动手学深度学习—卷积神经网络(原理解释+代码详解)
目录
- 1. 从全连接层到卷积层
- 2. 图像卷积
- 2.1 互相关运算
- 2.2 卷积层
- 2.3 图像中目标的边缘检测
- 2.4 学习卷积核
- 2.5 特征映射和感受野
- 3. 填充和步幅
- 3.1 填充
- 3.2 步幅
- 4. 多输入多输出通道
- 4.1 多输入通道
- 4.2 多输出通道
- 4.3 1×1卷积核
- 5. 汇聚层
- 5.1 最大汇聚层和平均汇聚层
- 5.2 填充和步幅
- 5.3 多个通道
1. 从全连接层到卷积层
- 多层感知机对图像处理是百万维度,模型不可实现。
- 如果要在图片中找到某个物体,寻找方法应该和物体位置无关。
适合计算机视觉的神经网络架构:
- 平移不变性:不管检测对象出现在图像中的哪个位置,神经网络前几层应该对相同图像区域有相似的反应。
- 局部性:神经网络的前面几层应该只探索输入图像中的局部区域,而不过度在意图像中相隔较远区域的关系。
2. 图像卷积
2.1 互相关运算
严格来说,卷积层所表达的运算其实是互相关运算。
不同颜色所选的区域与同一个卷积核做互相关运算,最后得到输出。


同理,卷积核滑动进行互相关运算。最终得到高度为2,宽度为2的输出。

输出大小:
"""定义corr2d函数:1、该函数接受输入张量X和卷积核张量K,并返回输出张量Y2、输出大小 = 输入大小n(k)×n(w) - 卷积核大小k(h)×k(w)3、即:(n(k)-k(h)+1) × (n(w)-k(w)+1 )
"""
import torch
from torch import nn
from d2l import torch as d2ldef corr2d(X, K): #@save"""计算二维互相关运算"""# 卷积核的高度h和宽度w,K指卷积核Kernelh, w = K.shape# 设置输出Y的大小,用0进行填充Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))# 对局部区域做互相关运算for i in range(Y.shape[0]):for j in range(Y.shape[1]):Y[i, j] = (X[i:i + h, j:j + w] * K).sum()return Y
对上图进行验证

2.2 卷积层
定义卷积层Conv2D:
- 卷积层对输入和卷积核权重进行互相关运算;
- 并在添加标量偏置之后产生输出。
"""定义卷积层Conv2D:1、卷积层对输入和卷积核权重进行互相关运算;2、并在添加标量偏置之后产生输出。
"""
class Conv2D(nn.Module):def __init__(self, kernel_size):super().__init__()# 设置权重self.weight = nn.Parameter(torch.rand(kernel_size))# 设置偏置self.bias = nn.Parameter(torch.zeros(1))# corr2d(X, K)def forward(self, x):return corr2d(x, self.weight) + self.bias
2.3 图像中目标的边缘检测
# 卷积层的一个简单应用:通过找到像素变化的位置,来检测图像中不同颜色的边缘。
# 1、构造一个6×8像素的黑白图像
X = torch.ones((6, 8))
X[:, 2:6] = 0
X

# 2、我们构造一个高度为1、宽度为2的卷积核K(水平相邻元素相同输出为0)
K = torch.tensor([[1.0, -1.0]])Y = corr2d(X, K)
Y

2.4 学习卷积核
"""由X生成Y的卷积核:1、构造一个卷积层,并将其卷积核初始化为随机张量;2、在每次迭代中,比较Y与卷积层输出的平方误差,然后计算梯度来更新卷积核;3、使用内置的二维卷积层,并忽略偏置。
"""
# 构造一个二维卷积层,它具有1个输出通道和形状为(1,2)的卷积核
conv2d = nn.Conv2d(1, 1, kernel_size=(1, 2), bias=False)# 这个二维卷积层使用四维输入和输出格式(批量大小、通道、高度、宽度),
# 其中批量大小和通道数都为1
X = X.reshape((1, 1, 6, 8))
Y = Y.reshape((1, 1, 6, 7))
lr = 3e-2 # 学习率# 进行训练,轮数为10。计算梯度并进行更新,输出loss
for i in range(10):# 定义损失函数:交叉熵损失Y_hat = conv2d(X)l = (Y_hat - Y) ** 2# 梯度置零conv2d.zero_grad()l.sum().backward()# 迭代卷积核# 梯度更新:w = w - lr * w'conv2d.weight.data[:] -= lr * conv2d.weight.grad# 每隔2轮输出一次if(i + 1) % 2 ==0:print(f'epoch{i+1}, loss{l.sum():.3f}')
这里可以看到学习的卷积核接近之前边缘检测的卷积核。

2.5 特征映射和感受野
- 输出的卷积层有时被称为特征映射。
- 在卷积神经网络中,对于某一层的任意元素x,其感受野是指在前向传播期间可能影响x计算的所有元素。
3. 填充和步幅
- 问题一:应用了连续卷积,最终得到的输出远小于输入大小,使得原始图像的边界丢失了许多有用信息,我们希望输入大小和输出大小相同?
解决:填充:在输入图像的边界填充元素(通常填充元素是0)- 问题二:有时原始的输入分辨率十分冗余,我们可能希望大幅降低图像的宽度和高度?
解决:步幅:设置卷积核滑动的步幅来减少采样次数- 问题三:卷积核为什么一般选择奇数?
解决:保持空间维度的同时,我们可以在顶部和底部填充相同数量的行,在左侧和右侧填充相同数量的列。
3.1 填充
填充(padding):在输入图像的边界填充元素(通常填充元素是0)


"""填充:1、输入给定8×8,输出要求8×82、卷积核的大小为3×3,所有侧边填充1个像素
"""
import torch
from torch import nn# 为了方便起见,我们定义了一个计算卷积层的函数。
# 此函数初始化卷积层权重,并对输入和输出提高和缩减相应的维数
def comp_conv2d(conv2d, X):# 这里的(1,1)表示批量大小和通道数都是1X = X.reshape((1, 1) + X.shape)Y = conv2d(X)# 省略前两个维度:批量大小和通道(1, 1, 8, 8)return Y.reshape(Y.shape[2:])conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)
X = torch.rand(size=(8, 8))
print(X)
print(conv2d)
print(comp_conv2d(conv2d, X))
comp_conv2d(conv2d, X).shape

# 卷积核为5×3时,为了使输入和输出相同,高度填充2,宽度填充1
conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))
comp_conv2d(conv2d, X).shape

3.2 步幅
步幅(stride):每次滑动元素的数量

"""步幅:1、每次滑动元素的数量;2、为了高效计算或是缩减采样次数,卷积窗口可以跳过中间位置,每次滑动多个元素。
"""
# 将高度和宽度的步幅设置为2,从而将输入的高度和宽度减半
# (8 + 2 - 3) / 2 = 4
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
comp_conv2d(conv2d, X).shape

4. 多输入多输出通道
4.1 多输入通道
当输入包含多个通道时,需要构造一个与输入数据具有相同输入通道数的卷积核,以便与输入数据进行互相关运算。

import torch
from d2l import torch as d2ldef corr2d_multi_in(X, K):# 先遍历“X”和“K”的第0个维度(通道维度),再把它们加在一起return sum(d2l.corr2d(x, k) for x, k in zip(X, K))# 构造输入张量X和核张量K,以验证互相关运算的输出
X = torch.tensor([[[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]],[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]])
K = torch.tensor([[[0.0 ,1.0], [2.0, 3.0]],[[1.0, 2.0], [3.0, 4.0]]])corr2d_muti_in(X, K)

4.2 多输出通道
多输出通道:
- 在最流行的神经网络架构中,随着神经网络层数的加深,我们常会增加输出通道的维数,通过减少空间分辨率以获得更大的通道深度。
- 将每个通道看作对不同特征的响应。
# 实现一个计算多个通道的输出的互相关函数
def corr2d_multi_in_out(X, K):# 迭代“K”的第0个维度,每次都对输入“X”执行互相关运算。# 最后将所有结果都叠加在一起return torch.stack([corr2d_multi_in(X, k) for k in K], 0)# 通过将核张量K与K+1(K中每个元素加1)和K+2连接起来,构造了一个具有3个输出通道的卷积核。
K = torch.stack((K, K + 1, K + 2), 0)# (输出通道数,输入通道数,高度,宽度)
K.shape

4.3 1×1卷积核
- 1×1卷积核被经常用来改变通道,相当于全连接层
- 可以对输入和输出的形状进行调整
# 使用全连接层实现1×1卷积
def corr2d_multi_in_out_1x1(X, K):c_i, h, w = X.shape# K:(输出通道,输入通道,高度,宽度)c_o = K.shape[0]X = X.reshape((c_i, h * w))K = K.reshape((c_o, c_i))# 全连接层中的矩阵乘法Y = torch.matmul(K, X)return Y.reshape((c_o, h, w))X = torch.normal(0, 1, (3, 3, 3))
K = torch.normal(0, 1, (2, 3, 1, 1))Y1 = corr2d_multi_in_out_1x1(X, K)
Y2 = corr2d_multi_in_out(X, K)
assert float(torch.abs(Y1 - Y2).sum()) < 1e-6
print(Y1)
print(Y2)

5. 汇聚层
通过逐渐聚合信息,生成越来越粗糙的映射,最终实现学习全局表示的目标,同时将卷积图层的所有优势保留在中间层。
汇聚(pooling)层(也叫做池化层):
- 降低卷积层对位置的敏感性
- 降低对空间降采样表示的敏感性
5.1 最大汇聚层和平均汇聚层
汇聚层与卷积层的原理大体相似,只不过把互相关运算换成求最大值或者求平均值


# 最大汇聚层和平均汇聚层
"""定义汇聚层:1、设置汇聚层与输出的大小2、设置模式:大汇聚层和平均汇聚层
"""
import torch
from torch import nn
from d2l import torch as d2l# 默认为最大汇聚层
def pool2d(X, pool_size, mode='max'):# 获取汇聚层的高度和宽度p_h, p_w = pool_size# 设置输出层Y的高度和宽度Y = torch.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w + 1))# 进行遍历,相当于对矩阵的局部区域[i:i+p_h, j:j+p_w]求最大值/平均值for i in range(Y.shape[0]):for j in range(Y.shape[1]):if mode == 'max':Y[i, j] = X[i: i + p_h, j: j + p_w].max()if mode == 'avg':Y[i, j] = X[i: i + p_h, j: j + p_w].mean()return Y# 构建输入张量X,验证二维最大汇聚层输出
X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
print(X)
print('最大汇聚层:\n', pool2d(X, (2, 2)))
print('平均汇聚层:\n', pool2d(X, (2, 2), 'avg'))
# print(f'最大汇聚层:{'\n'+pool2d(X, (2, 2))}')
# print(f'平均汇聚层:{pool2d(X, (2, 2), 'avg')}')

5.2 填充和步幅
与卷积层一样,汇聚层也可以改变输出形状
# 构造了一个输入张量X,它有四个维度,其中样本数和通道数都是1
X = torch.arange(16, dtype=torch.float32).reshape((1, 1, 4, 4))
X

5.3 多个通道
多个通道:
- 在处理多通道输入数据时,汇聚层在每个输入通道上单独运算,而不是像卷积层一样在通道上对输入进行汇总
- 汇聚层的输出通道数与输入通道数相同。
"""多个通道:1、在处理多通道输入数据时,汇聚层在每个输入通道上单独运算,而不是像卷积层一样在通道上对输入进行汇总。2、汇聚层的输出通道数与输入通道数相同。
"""
X = torch.cat((X, X + 1), 1)
X
pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)

相关文章:
动手学深度学习—卷积神经网络(原理解释+代码详解)
目录 1. 从全连接层到卷积层2. 图像卷积2.1 互相关运算2.2 卷积层2.3 图像中目标的边缘检测2.4 学习卷积核2.5 特征映射和感受野 3. 填充和步幅3.1 填充3.2 步幅 4. 多输入多输出通道4.1 多输入通道4.2 多输出通道4.3 11卷积核 5. 汇聚层5.1 最大汇聚层和平均汇聚层5.2 填充和步…...
环球数科、BUFFALO面试(部分)
环球数科 系统复杂且需求迭代频繁,如何维护微服务之间的接口调用关系? API接口在设计的时候需要大量的需求文档,而且文档也需要不断维护。如何高效维护API文档就很重要了。以下是一些常见的API管理工具:Swagger:Swag…...
RabbitMQ快速入门
文章目录 1、RabbitMQ的概述1.1、什么是消息队列?1.2、为什么要使用消息队列?1.3、RabbitMQ的特点: 2、RabbitMQ的安装2.1 下载与安装2.2 常用命令 3、RabbitMQ消息发送和接受3.1 消息发送和接受机制3.2 AMQP的消息路由3.3 Exchange(交换机)的…...
使用Git在GitHub上部署静态页面
在GitHub中,我们可以将自己的静态页面部署到GitHub中,它会给我们提供一个地址使得我们的页面变成一个真正的网站,可以供用户访问。 一、在GitHub下创建仓库 二、将项目部署到GitHub上 1. 初始化Git仓库 2. 提交代码 3. 关联远程仓库 在Gi…...
SQL-每日一题【1084. 销售分析III】
题目 Table: Product Table: Sales 编写一个SQL查询,报告2019年春季才售出的产品。即仅在2019-01-01至2019-03-31(含)之间出售的商品。 以 任意顺序 返回结果表。 查询结果格式如下所示。 示例 1: 解题思路 前置知识 between and between…...
Redis 软件包,在 CentOS 7 中安装 Redis
Download | Redis 1. 解压 Redis 软件包。假设你的 Redis 软件包名为 redis.tar.gz,进入redis.tar.gz所在目录下 ,可以使用以下命令进行解压: tar xzf redis.tar.gz 2. 切换到 Redis 软件包的解压目录。假设解压后的目录名为 redis…...
01.Redis实现发送验证码保存功能
学习目标: 提示:学习如何利用Redis来实现发送验证码功能 学习产出: 1. 准备pom环境 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><…...
C++STL——deque容器详解
纵有疾风起,人生不言弃。本文篇幅较长,如有错误请不吝赐教,感谢支持。 💬文章目录 一.deque容器的基本概念二.deque容器常用操作①deque构造函数②deque元素操作③deque赋值操作④deque交换操作⑤deque大小操作⑥deque插入和删除…...
docker 哨兵模式和集群模式安装Redis7.0.12
docker 哨兵模式和集群模式安装Redis7.0.12 1.下载镜像 1.1 配置阿里云加速源 墙外能访问https://hub.docker.com/_/redis 的可跳过 https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors 登录后选择左侧的镜像工具>镜像加速器,获取加速器地址&#…...
go nil 与零值
go nil 与零值 区别描述: 在Go语言中,nil和零值是两个不同的概念,它们在处理空值或未初始化值时有不同的应用场景。 nil: 在Go语言中,nil表示指针类型的零值或者interface、function、map、slice、channel、error类…...
puppeteer监听response并封装为express服务调用
const express require(express); const puppeteer require(puppeteer); const app express(); let browser; // 声明一个全局变量来存储浏览器实例app.get(/getInfo, async (req, res) > {try {const page_param req.query.page; // 获取名为"page"的查询参数…...
kubernetes之Ingress
一、背景 Ingress是k8s中实现7层负载的实现方式,是公开集群外部流量到集群内服务的HTTP和HTTPS路由 二、Ingress基础 通常Ingress实现由Ingress 控制器和Ingress组成,Ingress控制器负责具体实现反向代理及负载均衡,Ingress负责定义匹配规则和…...
前端实现打印1 - 使用 iframe 实现 并 分页打印
目录 打印代码对话框预览打印预览 打印代码 <!-- 打印 --> <template><el-dialogtitle"打印":visible.sync"dialogVisible"width"50%"top"7vh"append-to-bodyclose"handleClose"><div ref"print…...
MIAOYUN获评“2023年度一云多芯稳定安全运行优秀案例”
2023年7月25日至26日,由中国信息通信研究院(简称“中国信通院”)、中国通信标准化协会主办的以“云领创新,算启新篇”为主题的“2023可信云大会”在北京成功举办。会上公布了多项前瞻领域的评估结果和2023年度最佳实践案例&#x…...
论文代码学习—HiFi-GAN(4)——模型训练函数train文件具体解析
文章目录 引言正文模型训练代码整体训练过程具体训练细节具体运行流程 多GPU编程main函数(通用代码)完整代码 总结引用 引言 这里翻译了HiFi-GAN这篇论文的具体内容,具体链接。这篇文章还是学到了很多东西,从整体上说,…...
安防视频综合管理合平台EasyCVR可支持的视频播放协议有哪些?
EasyDarwin开源流媒体视频EasyCVR安防监控平台可提供视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、云台控制、语音对讲、智能分析等能力。 视频监控综合管理平台EasyCVR具备视频融合能力,平台基于云边端一体化架构,具有强大的…...
一张表格讲明白white-space属性。html如何识别\n\r,让这些特殊换行符换行。
大多数标签在展示文本内容的时候都会默认把文本中的空白和换行符去掉,这的确大大的使得文本的排版更加美观了,也怎加了区域的利用率,可是就有一些需求是需要原原本本的展示出原汁原味的文本格式。那该如何展示出文本的内在格式呢?…...
【Linux】编写shell脚本将项目前一天打印的日志进行提取,并且单独保存
业务场景:又到了熟悉的业务场景环节,其实应用上有很多,我们为了方便提取日志中部分关键的内容,对接给其他人也好,方便自己统计也罢,都会比每次我们都去服务器上及时查看,或者下载全部日志再筛选…...
快速搭建单机RocketMQ服务(开发环境)
一、什么是RocketMQ RocketMQ是阿里巴巴开源的一个消息中间件,在阿里内部历经了双十一等很多高并发场景的考验,能够处理亿万级别的消息。2016年开源后捐赠给Apache,现在是Apache的一个顶级项目。 早期阿里使用ActiveMQ,…...
Centos7搭建Apache Storm 集群运行环境
文章目录 1. 安装 Java2. 下载并解压 Storm3. 配置环境变量4. 配置 ZooKeeper5. 配置 Stormstorm.yaml自定义 storm.yamlstorm-env.shlogback/cluster.xml 6. 启动 Storm 集群7. 验证 1. 安装 Java Storm 运行在 Java 平台上,因此需要先安装 Java。你可以使用以下命…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...
用递归算法解锁「子集」问题 —— LeetCode 78题解析
文章目录 一、题目介绍二、递归思路详解:从决策树开始理解三、解法一:二叉决策树 DFS四、解法二:组合式回溯写法(推荐)五、解法对比 递归算法是编程中一种非常强大且常见的思想,它能够优雅地解决很多复杂的…...
Copilot for Xcode (iOS的 AI辅助编程)
Copilot for Xcode 简介Copilot下载与安装 体验环境要求下载最新的安装包安装登录系统权限设置 AI辅助编程生成注释代码补全简单需求代码生成辅助编程行间代码生成注释联想 代码生成 总结 简介 尝试使用了Copilot,它能根据上下文补全代码,快速生成常用…...
spring boot使用HttpServletResponse实现sse后端流式输出消息
1.以前只是看过SSE的相关文章,没有具体实践,这次接入AI大模型使用到了流式输出,涉及到给前端流式返回,所以记录一下。 2.resp要设置为text/event-stream resp.setContentType("text/event-stream"); resp.setCharacter…...

