DL基础补全计划(六)---卷积和池化

2024-06-16 06:58

本文主要是介绍DL基础补全计划(六)---卷积和池化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

PS:要转载请注明出处,本人版权所有。

PS: 这个只是基于《我自己》的理解,

如果和你的原则及想法相冲突,请谅解,勿喷。

环境说明
  • Windows 10
  • VSCode
  • Python 3.8.10
  • Pytorch 1.8.1
  • Cuda 10.2

前言


  本文是此基础补全计划的最终篇,因为从我的角度来说,如果前面这些基础知识都能够了解及理解,再加上本文的这篇基础知识,那么我们算是小半只脚踏入了大门。从这个时候,其实我们就已经可以做图像上的基本的分类任务了。除了分类任务,我们还有两类重要的图像任务是目标检测和图像分割,这两项任务都和分类任务有一定的关联,可以说,分类可以说是这两类的基础。

  卷积神经网络是一个专门为处理图像数据的网络。下面我们简单的来看看卷积、池化的含义和怎么计算的,然后我们通过一个LeNet5的经典网络,训练一个分类模型。





卷积


  卷积是一种运算,类似加减乘除。卷积是一种运算,类似加减乘除。卷积是一种运算,类似加减乘除。重要的事情说三次。

  在数学上的定义是:连续n的情况 ( f ∗ g ) ( x ) = ∫ f ( n ) g ( x − n ) d n (f*g)(x) = \int f(n)g(x-n)dn (fg)(x)=f(n)g(xn)dn, 离散n的情况 ( f ∗ g ) ( x ) = ∑ n f ( n ) g ( x − n ) (f*g)(x) = \sum\limits_{n} f(n)g(x-n) (fg)(x)=nf(n)g(xn)。从这里我们可以看到,卷积就是测量函数f和函数g的翻转且平移x后的重叠。其二维离散a,b的表达是 ( f ∗ g ) ( x 1 , x 2 ) = ∑ a ∑ b f ( a , b ) g ( x 1 − a , x 2 − b ) (f*g)(x1,x2) = \sum\limits_{a}\sum\limits_{b} f(a, b)g(x1-a, x2-b) (fg)(x1,x2)=abf(a,b)g(x1a,x2b)

  卷积是一种运算,类似加减乘除。卷积是一种运算,类似加减乘除。卷积是一种运算,类似加减乘除。重要的事情再说三次。

  我们再次想一想,在之前的文章中,我们普遍都建立了一种想法是,把输入数据拉成一条直线输入的,这就意味着我们在之前的任务里面只建立了相邻输入数据之间的左右关联。但是我们可以想一想,是不是所有的数据只建立左右关联就行了呢?显而易见的,并不是这样的,比如我们图片,可能上下左右4个像素加起来才是一个猫,如果我们只关联了左右,那么它可能是狗或者猫。那么我们应该通过什么样的方式来对图片像素的这种二维关联性进行描述或者计算呢?这种方法就是卷积运算。

  卷积网上有许许多多的介绍,大家都做了许多详细的解答,包含信号分析、复利、概率以及图像滤波等等方面的解释。我个人认为我们可以抛开这些方面,从数据之间的关联性来看这个问题可能是最好理解的,因为我们之前只关注了数据之间左右关联,我们应该同时关注上下左右的关联才对,我们要从空间的角度来考虑数据之间的关联性。而卷积作为一种数学运算,他恰好是计算了数据的上下左右关联性,因此卷积这种数学运算很适合拿来代替之前的一条线的线性运算。

  下面我们来看一下一个基本的卷积计算过程是什么样子的。



图像边缘检测实例

  计算代码如下:

def corr2d(X, K): #@save"""计算⼆维互相关运算。"""h, w = K.shapeY = np.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_X = np.ones((6, 8))
_X[0:2, 2:6] = 0
_X[3:, 2:6] = 0
print(_X)
_K = np.array([[1.0, -1.0]])
_Y = corr2d(_X, _K)
print(_Y)
_Y = corr2d(_X, _K.T)
print(_Y)

  结果如图:

rep_img

  我们可以分别的看到,图像边缘的数值在经过我们手动构造的滤波器后,成功的检测到边缘信息。

  在实际情况中,我们可能要学习边缘,角点等等特征,这个时候我们不可能手动去构造我们的滤波器,那么我们可不可以通过学习的方式把滤波器学习出来呢?下面通过实例来演示:

_X = np.ones((6, 8))
_X[0:2, 2:6] = 0
_X[3:, 2:6] = 0
print(_X)
_K = np.array([[1.0, -1.0]])
_Y = corr2d(_X, _K)
print(_Y)
# _Y = corr2d(_X, _K.T)
# print(_Y)X = torch.from_numpy(_X)
X.requires_grad = True
X = X.to(dtype=torch.float32)
X = X.reshape(1, 1, 6, 8)Y = torch.from_numpy(_Y)
Y.requires_grad = Trueconv2d = torch.nn.Conv2d(1, 1, (1, 2), bias=False)for i in range(20):y_train = conv2d(X)l = (y_train - Y)**2conv2d.zero_grad()# print(l.shape)l.backward(torch.ones_like(l))# print(conv2d.weight)with torch.no_grad():# print('grad = ', conv2d.weight.grad)conv2d.weight[:] -= 0.02 * conv2d.weight.grad# print(conv2d.weight)# print(conv2d.weight.shape)if (i + 1) % 2 == 0:print(f'batch {i+1}, loss {float(l.sum()):.3f}')print(conv2d.weight)

  结果如图:

rep_img

  我们通过corr2d函数构造出特征Y,然后我们通过训练特征Y,我们可以看到最终卷积层的权重就是接近与1和-1,恰好等于我们构造的特殊滤波器。

  这个实例说明了,我们可以通过学习的方式来学习出一个我们想要的滤波器,不需要手动构造。

  此外卷积还有卷积核、步长、填充等等资料,我就不造轮子了,网上有很多大佬写的很好的,大家去看看。此外这里有个公式非常有用:N=(W-K+2P)/S+1。





池化


  我们在上文知道了卷积的输出结果代表了一片上下左右数据的关联性,比如一个像素和之前的9个像素有关联,比如一个 9 ∗ 9 9*9 99的图,经过一个卷积后,假如还是 9 ∗ 9 9*9 99,这个时候输出的 9 ∗ 9 9*9 99里面的每个像素我们已经和之前对应位置的一片像素建立了关联。但是某些时候,我们希望这种关联性聚合起来,通过求最大值或者平均等等,这就是池化的概念。以之前例子为例:卷积输出了 9 ∗ 9 9*9 99的像素,经过池化之后,假如变成了 3 ∗ 3 3*3 33,我们可以看到池化输出的每个像素代表之前卷积输出的 3 ∗ 3 3*3 33个像素,这代表我们的信息聚集了,因为一个像素代表了上一层的多个像素。

  注意池化,我们还可以从视野的角度来看待,还是和上面的例子一样,假如原图上的猫是 9 ∗ 9 9*9 99的像素,经过卷积池化之后,假如变成了 3 ∗ 3 3*3 33, 这意味着我们从像素的角度来说,之前81个像素代表猫,现在9个像素就可以代表了,也就是之前的一个像素和现在的一个像素代表的原图视野不一样了,形成了视野放大的感觉。但是有一个缺点就是,这可能导致小目标丢失了,这个在目标检测里面会关注到。





一个经典神经网络LeNet5


  在2017年12月份,我的这篇文章中《LeNet-5 论文及原理分析(笨鸟角度)》 ( https://blog.csdn.net/u011728480/article/details/78799672 )其实当时我为了学习一些基本知识,也对LeNet5的论文中网络结构部分做了细致的分析。

  注意本文中的C3层和论文中的C3层不一样。本文的C3层是 16 ∗ 6 ∗ ( 5 ∗ 5 + 1 ) = 2496 16*6*(5*5+1) = 2496 166(55+1)=2496个参数。论文原文是 6 ∗ ( 3 ∗ 5 ∗ 5 + 1 ) + 6 ∗ ( 4 ∗ 5 ∗ 5 + 1 ) + 3 ∗ ( 4 ∗ 5 ∗ 5 + 1 ) + 1 ∗ ( 6 ∗ 5 ∗ 5 + 1 ) = 1516 6*(3*5*5+1)+6*(4*5*5+1)+3*(4*5*5+1)+1* (6*5*5+1)=1516 6(355+1)+6(455+1)+3(455+1)+1(655+1)=1516个参数。

  训练代码如下:

import numpy as np
from numpy.lib.utils import lookfor
import torchfrom torchvision.transforms import ToTensor
import os
import torch
from torch import nn
from torch.nn.modules import activation
from torch.nn.modules import linear
from torch.nn.modules.linear import Linear
from torch.utils.data import DataLoader
from torchvision import datasets, transformsimport visdomvis = visdom.Visdom(env='main')title = 'LeNet5 on ' + 'FashionMNIST'
legend = ['TrainLoss', 'TestLoss', 'TestAcc']epoch_plot_window = vis.line(        X=torch.zeros((1, 3)).cpu(),Y=torch.zeros((1, 3)).cpu(),win='epoch_win',opts=dict(xlabel='Epoch',ylabel='Loss/Acc',title=title,legend=legend))def corr2d(X, W): #@save"""计算⼆维互相关运算。"""h, w = W.shapeY = np.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] * W).sum()return Ydef TrainConv2d():_X = np.ones((6, 8))_X[0:2, 2:6] = 0_X[3:, 2:6] = 0print(_X)_K = np.array([[1.0, -1.0]])_Y = corr2d(_X, _K)print(_Y)# _Y = corr2d(_X, _K.T)# print(_Y)X = torch.from_numpy(_X)X.requires_grad = TrueX = X.to(dtype=torch.float32)X = X.reshape(1, 1, 6, 8)Y = torch.from_numpy(_Y)Y.requires_grad = Trueconv2d = torch.nn.Conv2d(1, 1, (1, 2), bias=False)for i in range(20):y_train = conv2d(X)l = (y_train - Y)**2conv2d.zero_grad()# print(l.shape)l.backward(torch.ones_like(l))# print(conv2d.weight)with torch.no_grad():# print('grad = ', conv2d.weight.grad)conv2d.weight[:] -= 0.02 * conv2d.weight.grad# print(conv2d.weight)# print(conv2d.weight.shape)if (i + 1) % 2 == 0:print(f'batch {i+1}, loss {float(l.sum()):.3f}')print(conv2d.weight)class NeuralNetwork(nn.Module):def __init__(self):super(NeuralNetwork, self).__init__()self.lenet5 = nn.Sequential(# 6*28*28---->6*28*28nn.Conv2d(1, 6, (5, 5), stride=1, padding=2),nn.Sigmoid(),# 6*28*28----->6*14*14nn.AvgPool2d((2, 2), stride=2, padding=0),# 6*14*14----->16*10*10nn.Conv2d(6, 16, (5, 5), stride=1),nn.Sigmoid(),# 16*10*10------>16*5*5nn.AvgPool2d((2, 2), stride=2, padding=0),nn.Flatten(),nn.Linear(16*5*5, 1*120),nn.Sigmoid(),nn.Linear(1*120, 1*84),nn.Sigmoid(),nn.Linear(1*84, 1*10))def forward(self, x):logits = self.lenet5(x)return logitsdef LoadFashionMNISTByTorchApi():# 60000*28*28training_data = datasets.FashionMNIST(root="..\data",train=True,download=True,transform=ToTensor())# 10000*28*28test_data = datasets.FashionMNIST(root="..\data",train=False,download=True,transform=ToTensor())# labels_map = {#     0: "T-Shirt",#     1: "Trouser",#     2: "Pullover",#     3: "Dress",#     4: "Coat",#     5: "Sandal",#     6: "Shirt",#     7: "Sneaker",#     8: "Bag",#     9: "Ankle Boot",# }# figure = plt.figure(figsize=(8, 8))# cols, rows = 3, 3# for i in range(1, cols * rows + 1):#     sample_idx = torch.randint(len(training_data), size=(1,)).item()#     img, label = training_data[sample_idx]#     figure.add_subplot(rows, cols, i)#     plt.title(labels_map[label])#     plt.axis("off")#     plt.imshow(img.squeeze(), cmap="gray")# plt.show()return training_data, test_datadef train_loop(dataloader, model, loss_fn, optimizer):size = len(dataloader.dataset)num_batches = len(dataloader)loss_sum = 0for batch, (X, y) in enumerate(dataloader):# move X, y to gpuif torch.cuda.is_available():X = X.to('cuda')y = y.to('cuda')# Compute prediction and losspred = model(X)loss = loss_fn(pred, y)# Backpropagationoptimizer.zero_grad()loss.backward()optimizer.step()loss_sum += loss.item()if batch % 100 == 0:loss1, current = loss.item(), batch * len(X)print(f"loss: {loss1:>7f}  [{current:>5d}/{size:>5d}]")return loss_sum/num_batchesdef test_loop(dataloader, model, loss_fn):size = len(dataloader.dataset)num_batches = len(dataloader)test_loss, correct = 0, 0with torch.no_grad():for X, y in dataloader:# move X, y to gpuif torch.cuda.is_available():X = X.to('cuda')y = y.to('cuda')pred = model(X)test_loss += loss_fn(pred, y).item()correct += (pred.argmax(1) == y).type(torch.float).sum().item()test_loss /= num_batchescorrect /= sizeprint(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")return test_loss, correctif __name__ == '__main__':# TrainConv2d()device = 'cuda' if torch.cuda.is_available() else 'cpu'print('Using {} device'.format(device))def init_weights(m):if type(m) == nn.Linear or type(m) == nn.Conv2d:nn.init.xavier_uniform_(m.weight)model = NeuralNetwork()model.apply(init_weights)model = model.to(device)print(model)batch_size = 200learning_rate = 0.9training_data, test_data = LoadFashionMNISTByTorchApi()train_dataloader = DataLoader(training_data, batch_size, shuffle=True)test_dataloader = DataLoader(test_data, batch_size, shuffle=True)loss_fn = nn.CrossEntropyLoss()optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)epochs = 1000model.train()for t in range(epochs):print(f"Epoch {t+1}\n-------------------------------")train_loss = train_loop(train_dataloader, model, loss_fn, optimizer)test_loss, test_acc = test_loop(test_dataloader, model, loss_fn)vis.line(np.array([train_loss, test_loss, test_acc]).reshape(1, 3), np.ones((1, 3))*t, win='epoch_win', update=None if t == 0 else 'append', opts=dict(xlabel='Epoch',ylabel='Loss/Acc',title=title,legend=legend))print("Done!")# only save paramtorch.save(model.state_dict(), 'lenet5.pth')# save param and nettorch.save(model, 'lenet5-all.pth')# export onnxinput_image = torch.zeros((1,1,28,28))input_image = input_image.to(device)torch.onnx.export(model, input_image, 'model.onnx')

  结果如图:

rep_img

  我们从训练可视化界面上可以看到,我们的模型确实是收敛了,但是不幸的是准确率大概有90%左右,而且存在过拟合现象。注意这里我们这个模型,由于有Sigmoid层,导致了很容易出现梯度消失的情况,为了加快训练,所以学习率设置的很大。





后记


  整理本系列的基础知识的原因是需要加深对深度学习的理解。同时跟着参考资料,重复试验,重复运行。对我个人而言,只有真实的写了代码之后,才能够理解的更加透彻。

  本文也是此系列的终篇,以后更新随缘。

参考文献

  • https://github.com/d2l-ai/d2l-zh/releases (V1.0.0)
  • https://github.com/d2l-ai/d2l-zh/releases (V2.0.0 alpha1)
  • https://blog.csdn.net/u011728480/article/details/78799672 (《LeNet-5 论文及原理分析(笨鸟角度)》)



打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)
qrc_img

PS: 请尊重原创,不喜勿喷。

PS: 要转载请注明出处,本人版权所有。

PS: 有问题请留言,看到后我会第一时间回复。

这篇关于DL基础补全计划(六)---卷积和池化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1065762

相关文章

RedHat运维-Linux文本操作基础-AWK进阶

你不用整理,跟着敲一遍,有个印象,然后把它保存到本地,以后要用再去看,如果有了新东西,你自个再添加。这是我参考牛客上的shell编程专项题,只不过换成了问答的方式而已。不用背,就算是我自己亲自敲,我现在好多也记不住。 1. 输出nowcoder.txt文件第5行的内容 2. 输出nowcoder.txt文件第6行的内容 3. 输出nowcoder.txt文件第7行的内容 4. 输出nowcode

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

零基础STM32单片机编程入门(一)初识STM32单片机

文章目录 一.概要二.单片机型号命名规则三.STM32F103系统架构四.STM32F103C8T6单片机启动流程五.STM32F103C8T6单片机主要外设资源六.编程过程中芯片数据手册的作用1.单片机外设资源情况2.STM32单片机内部框图3.STM32单片机管脚图4.STM32单片机每个管脚可配功能5.单片机功耗数据6.FALSH编程时间,擦写次数7.I/O高低电平电压表格8.外设接口

YOLOv8改进 | SPPF | 具有多尺度带孔卷积层的ASPP【CVPR2018】

💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏目录 :《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有40+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进——点击即可跳转 Atrous Spatial Pyramid Pooling (ASPP) 是一种在深度学习框架中用于语义分割的网络结构,它旨

ps基础入门

1.基础      1.1新建文件      1.2创建指定形状      1.4移动工具          1.41移动画布中的任意元素          1.42移动画布          1.43修改画布大小          1.44修改图像大小      1.5框选工具      1.6矩形工具      1.7图层          1.71图层颜色修改          1

[FPGA][基础模块]跨时钟域传播脉冲信号

clk_a 周期为10ns clk_b 周期为34ns 代码: module pulse(input clk_a,input clk_b,input signal_a,output reg signal_b);reg [4:0] signal_a_widen_maker = 0;reg signal_a_widen;always @(posedge clk_a)if(signal_a)

00 - React 基础

1. React 基础 安装react指令 可参考: 官网官网使用教程 如: npx create-react-app 项目名如:npx create-react-app react-redux-pro JSX JSX 是一种 JavaScript 的语法扩展,类似于 XML 或 HTML,允许我们在 JavaScript 代码中编写 HTML。 const element =

如何设置windows计划任务

如何设置windows计划任务 前言:在工作过程中写了一个python脚本,用于调用jira接口查询bug单数量,想要在本地定时任务执行,每天发送到钉钉群提醒,写下操作步骤用于记录。 1. 准备 Python 脚本 确保你的 Python 脚本已经保存到一个文件,比如 jira_reminder.py。 2. 创建批处理文件 为了方便任务计划程序运行 Python 脚本,创建一个批处理文

AI赋能天气:微软研究院发布首个大规模大气基础模型Aurora

编者按:气候变化日益加剧,高温、洪水、干旱,频率和强度不断增加的全球极端天气给整个人类社会都带来了难以估计的影响。这给现有的天气预测模型提出了更高的要求——这些模型要更准确地预测极端天气变化,为政府、企业和公众提供更可靠的信息,以便做出及时的准备和响应。为了应对这一挑战,微软研究院开发了首个大规模大气基础模型 Aurora,其超高的预测准确率、效率及计算速度,实现了目前最先进天气预测系统性能的显著

【软考】信息系统项目管理师(高项)备考笔记——信息系统项目管理基础

信息系统项目管理基础 日常笔记 项目的特点:临时性(一次性)、独特的产品、服务或成果、逐步完善、资源约束、目的性。 临时性是指每一个项目都有确定的开始和结束日期独特性,创造独特的可交付成果,如产品、服务或成果逐步完善意味着分步、连续的积累。例如,在项目早期,项目范围的说明是粗略的,随着项目团队对目标和可交付成果的理解更完整和深入时,项目的范围也就更具体和详细。 战略管理包括以下三个过程