Pytorch 卷积层

0. 环境介绍

环境使用 Kaggle 里免费建立的 Notebook

教程使用李沐老师的 动手学深度学习 网站和 视频讲解

小技巧:当遇到函数看不懂的时候可以按 Shift+Tab 查看函数详解。

1. 从全连接到卷积

多层感知机十分适合处理表格数据,其中行对应样本,列对应特征。 对于表格数据,我们寻找的模式可能涉及特征之间的交互,但是我们不能预先假设任何与特征交互相关的先验结构。 此时,多层感知机可能是最好的选择,然而对于高维感知数据(图片,视频等),这种缺少结构的网络可能会变得不实用。

:深度神经网络也不适合用于处理表格数据。
大家可以看一下以下资料:
深度神经网络为什么在表格数据上就是不行呢
论文地址

1.0 猫狗图像分类

假设有一个充分的猫狗照片数据集,每张照片具有百万级别的像素,这意味着网络的每次输入都有一百万(10610^6106)个维度(先不考虑 RGB 通道)。即使将隐藏层维度降低到 1000(103)1000(10^3)1000(103),这个全连接层也将有 106×103=10910^6 \times 10^3 = 10^9106×103=109 个参数。

参数量太多,需要大量的 GPU 资源和分布式优化训练的经验。

然而,如今人类和机器都能很好地区分猫和狗:这是因为图像中本就拥有丰富的结构,而这些结构可以被人类和机器学习模型使用。 卷积神经网络(convolutional neural networks,CNN)是机器学习利用自然图像中一些已知结构的创造性方法。

1.1 平移不变性和局部性

假设你想从一张图片中找到某个物体。 合理的假设是:无论哪种方法找到这个物体,都应该和物体的位置无关。

沃尔多游戏:在这个游戏中包含了许多充斥着活动的混乱场景,而沃尔多通常潜伏在一些不太可能的位置,读者的目标就是找出他。 尽管沃尔多的装扮很有特点,但是在眼花缭乱的场景中找到他也如大海捞针。 然而沃尔多的样子并不取决于他潜藏的地方,因此我们可以使用一个“沃尔多检测器”扫描图像。 该检测器将图像分割成多个区域,并为每个区域包含沃尔多的可能性打分。 卷积神经网络正是将空间不变性(spatial invariance)的这一概念系统化,从而基于这个模型使用较少的参数来学习有用的表示。

总结下来就是两个原则:

  1. 平移不变性(translation invariance):不管检测对象出现在图像中的哪个位置,神经网络的前面几层应该对相同的图像区域具有相似的反应,即为“平移不变性”。
  2. 局部性(locality):神经网络的前面几层应该只探索输入图像中的局部区域,而不过度在意图像中相隔较远区域的关系,这就是“局部性”原则。最终,可以聚合这些局部特征,以在整个图像级别进行预测。

1.2 多层感知机的限制

使用 [X]i,j[\mathbf{X}]_{i, j}[X]i,j​ 和 [H]i,j[\mathbf{H}]_{i, j}[H]i,j​ 分别表示输入图像和隐藏表示中位置 (i,j)(i, j)(i,j) 处的像素。
[H]i,j=[U]i,j+∑k∑l[W]i,j,k,l[X]k,l=[U]i,j+∑a∑b[V]i,j,a,b[X]i+a,j+b.\begin{aligned} \left[\mathbf{H}\right]_{i, j} &= [\mathbf{U}]_{i, j} + \sum_k \sum_l[\mathsf{W}]_{i, j, k, l} [\mathbf{X}]_{k, l}\\ &= [\mathbf{U}]_{i, j} + \sum_a \sum_b [\mathsf{V}]_{i, j, a, b} [\mathbf{X}]_{i+a, j+b}.\end{aligned} [H]i,j​​=[U]i,j​+k∑​l∑​[W]i,j,k,l​[X]k,l​=[U]i,j​+a∑​b∑​[V]i,j,a,b​[X]i+a,j+b​.​
为了使每个隐藏神经元都能接收到每个输入像素的信息,我们将参数从权重矩阵(如同我们先前在多层感知机中所做的那样)替换为四阶权重张量 WWW。 UUU 为偏置参数。aaa 和 bbb 通过在正偏移和负偏移之间移动覆盖了整个图像。 [V]i,j,a,b[\mathsf{V}]_{i, j, a, b}[V]i,j,a,b​ 表示像素 (i,j)(i, j)(i,j) 对于像素 (i+a,j+b)(i+a, j+b)(i+a,j+b) 的权重。

可以发现参数量很大。

1.3 引入平移不变性

意味着对象在输入 XXX 中的平移,应该仅导致隐藏层 HHH 中的平移。也就是说 VVV 和 UUU 不依赖于 (i,j)(i, j)(i,j) 的值,即 [V]i,j,a,b=[V]a,b[\mathsf{V}]_{i, j, a, b} = [\mathbf{V}]_{a, b}[V]i,j,a,b​=[V]a,b​。而且 UUU 为一个常数 uuu。
[H]i,j=u+∑a∑b[V]a,b[X]i+a,j+b.[\mathbf{H}]_{i, j} = u + \sum_a\sum_b [\mathbf{V}]_{a, b} [\mathbf{X}]_{i+a, j+b}. [H]i,j​=u+a∑​b∑​[V]a,b​[X]i+a,j+b​.
这就是卷积(convolution)。我们是在使用系数 [V]a,b[\mathbf{V}]_{a, b}[V]a,b​ 对位置 (i,j)(i, j)(i,j) 附近的像素 (i+a,j+b)(i+a, j+b)(i+a,j+b) 进行加权得到 [H]i,j[\mathbf{H}]_{i, j}[H]i,j​。

这样看的话,[V]a,b[\mathbf{V}]_{a, b}[V]a,b​ 的参数量比 [V]i,j,a,b[\mathsf{V}]_{i, j, a, b}[V]i,j,a,b​ 要少了很多。

1.4 引入局部性

为了收集训练参数 [H]i,j[\mathbf{H}]_{i, j}[H]i,j​ 的相关信息,我们不应偏离到距 (i,j)(i, j)(i,j) 很远的地方。这意味着在 ∣a∣>Δ|a|> \Delta∣a∣>Δ 或 ∣b∣>Δ|b|> \Delta∣b∣>Δ 的范围之外,我们可以设置 [V]a,b=0[\mathbf{V}]_{a, b} = 0[V]a,b​=0。因此,我们可以将 [H]i,j[\mathbf{H}]_{i, j}[H]i,j​ 重写为:
[H]i,j=u+∑a=−ΔΔ∑b=−ΔΔ[V]a,b[X]i+a,j+b.[\mathbf{H}]_{i, j} = u + \sum_{a = -\Delta}^{\Delta} \sum_{b = -\Delta}^{\Delta} [\mathbf{V}]_{a, b} [\mathbf{X}]_{i+a, j+b}. [H]i,j​=u+a=−Δ∑Δ​b=−Δ∑Δ​[V]a,b​[X]i+a,j+b​.

上式就是一个卷积层(convolutional layer),卷积神经网络(CNN)就是包含卷积层的一类特殊的神经网络。
VVV 被称为卷积核(convolution kernel)或者滤波器(filter),亦或简单地称之为该卷积层的权重,通常该权重是可学习的参数。

当图像处理的局部区域很小时,卷积神经网络与多层感知机的训练差异可能是巨大的:以前,多层感知机可能需要数十亿个参数来表示网络中的一层,而现在卷积神经网络通常只需要几百个参数,而且不需要改变输入或隐藏表示的维数。 参数大幅减少的代价是,我们的特征现在是平移不变的,并且当确定每个隐藏活性值时,每一层只包含局部的信息。 以上所有的权重学习都将依赖于归纳偏置。当这种偏置与现实相符时,我们就能得到样本有效的模型,并且这些模型能很好地泛化到未知数据中。 但如果这偏置与现实不符时,比如当图像不满足平移不变时,我们的模型可能难以拟合我们的训练数据。

2. 卷积层

卷积层严格来讲,是错误的叫法,因为它所表达的运算其实是交叉相关运算(cross-correlation),而不是卷积运算。

::
想了解卷积的意义,这里推荐 B 站 一位 up 主的视频:
从“卷积”、到“图像卷积操作”、再到“卷积神经网络”,“卷积”意义的3次改变

2.1 2D 卷积层

输入 XXX 是 (3×3)(3 \times 3)(3×3) 的张量,卷积核 WWW 为 (2×2)(2 \times 2)(2×2)。

输出 YYY 大小等于输入 XXX 大小 nh×nwn_h \times n_wnh​×nw​ 减去卷积核 WWW 大小 kh×kwk_h \times k_wkh​×kw​,即:
(nh−kh+1)×(nw−kw+1).(n_h-k_h+1) \times (n_w-k_w+1). (nh​−kh​+1)×(nw​−kw​+1).
然后再加上一个偏置项 bbb,YYY 表达式为:
Y=X★W+bY = X ★ W + b Y=X★W+b
★★★ 表示卷积运算,WWW 和 bbb 是可学习的参数。卷积核的大小 kh×kwk_h \times k_wkh​×kw​ 是超参数。

3. 图像卷积代码实现

3.1 2D 卷积运算

!pip install d2l
import torch
from torch import nn
from d2l import torch as d2ldef corr2d(X, K):  #@save"""计算二维互相关运算"""h, w = K.shape# 输出的形状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

验证上述实现的输出:

X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
corr2d(X, K)

3.2 2D卷积层

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))def forward(self, x):return corr2d(x, self.weight) + self.bias

3.3 图像中目标的边缘检测

X = torch.ones((6, 8))
X[:, 2:6] = 0
X


构造一个 (1×2)(1 \times 2)(1×2) 的卷积核 KKK,如果水平相邻的两元素相同,则输出为零,否则输出为非零。

K = torch.tensor([[1.0, -1.0]])

输出 YYY 中的 111 代表从白色到黑色的边缘,−1-1−1 代表从黑色到白色的边缘,其他情况的输出为 000。

Y = corr2d(X, K)
Y


现在我们将输入的二维图像转置,再运算。 其输出如下,之前检测到的垂直边缘消失了。 这个卷积核 KKK 只可以检测垂直边缘,无法检测水平边缘:

corr2d(X.t(), K)

3.4 学习由 XXX 生成 YYY 的卷积核 KKK

上一节(3.3)我们是设置的卷积核 KKK 的值,通过与 XXX 运算得到了 YYY,下面我们通过 XXX 和 YYY 训练学习出来 KKK。

我们先构造一个卷积层,并将其卷积核初始化为随机张量。接下来,在每次迭代中,我们比较 YYY 与卷积层输出的平方误差,然后计算梯度来更新卷积核。为了简单起见,我们在此使用内置的二维卷积层,并忽略偏置:

# 构造一个二维卷积层,它具有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  # 学习率for i in range(10):Y_hat = conv2d(X)l = (Y_hat - Y) ** 2conv2d.zero_grad()l.sum().backward()# 迭代卷积核conv2d.weight.data[:] -= lr * conv2d.weight.gradif (i + 1) % 2 == 0:print(f'epoch {i+1}, loss {l.sum():.3f}')

:关于为什么损失需要 sum() 之后再 backward()
参考 https://zhuanlan.zhihu.com/p/427853673

查看所学的卷积核的权重张量:

conv2d.weight.data.reshape((1, 2))

3.5 加入偏置 bbb 后训练

# 构造一个二维卷积层,它具有1个输出通道和形状为(1,2)的卷积核
conv2d = nn.Conv2d(1,1, kernel_size=(1, 2), bias=True)# 这个二维卷积层使用四维输入和输出格式(批量大小、通道、高度、宽度),
# 其中批量大小和通道数都为1
X = X.reshape((1, 1, 6, 8))
Y = Y.reshape((1, 1, 6, 7))
lr = 3e-2  # 学习率for i in range(10):Y_hat = conv2d(X)l = (Y_hat - Y) ** 2conv2d.zero_grad()l.sum().backward()# 迭代卷积核conv2d.weight.data[:] -= lr * conv2d.weight.gradconv2d.bias.data[:] -= lr * conv2d.bias.gradif (i + 1) % 2 == 0:print(f'epoch {i+1}, loss {l.sum():.3f}')


可以发现无法收敛,这个时候应该调小学习率 lr 并且增加训练 epoch 数量:

# 构造一个二维卷积层,它具有1个输出通道和形状为(1,2)的卷积核
conv2d = nn.Conv2d(1,1, kernel_size=(1, 2), bias=True)# 这个二维卷积层使用四维输入和输出格式(批量大小、通道、高度、宽度),
# 其中批量大小和通道数都为1
X = X.reshape((1, 1, 6, 8))
Y = Y.reshape((1, 1, 6, 7))
lr = 1e-2  # 学习率for i in range(30):Y_hat = conv2d(X)l = (Y_hat - Y) ** 2conv2d.zero_grad()l.sum().backward()# 迭代卷积核conv2d.weight.data[:] -= lr * conv2d.weight.gradconv2d.bias.data[:] -= lr * conv2d.bias.gradif (i + 1) % 2 == 0:print(f'epoch {i+1}, loss {l.sum():.3f}')print(conv2d.weight.data.reshape((1, 2)), conv2d.bias.data)

Pytorch 卷积层相关推荐

  1. (pytorch-深度学习系列)pytorch卷积层与池化层输出的尺寸的计算公式详解

    pytorch卷积层与池化层输出的尺寸的计算公式详解 要设计卷积神经网络的结构,必须匹配层与层之间的输入与输出的尺寸,这就需要较好的计算输出尺寸 先列出公式: 卷积后,池化后尺寸计算公式: (图像尺寸 ...

  2. Pytorch学习 - Task5 PyTorch卷积层原理和使用

    Pytorch学习 - Task5 PyTorch卷积层原理和使用 1. 卷积层 (1)介绍 (torch.nn下的) 1) class torch.nn.Conv1d() 一维卷积层 2) clas ...

  3. 卷积核权值初始化_Pytorch卷积层手动初始化权值的实例

    由于研究关系需要自己手动给卷积层初始化权值,但是好像博客上提到的相关文章比较少(大部分都只提到使用nn.init里的按照一定分布初始化方法),自己参考了下Pytorch的官方文档,发现有两种方法吧. ...

  4. pytorch神经网络之卷积层与全连接层参数的设置

    当使用pytorch写网络结构的时候,本人发现在卷积层与第一个全连接层的全连接层的input_features不知道该写多少?一开始本人的做法是对着pytorch官网的公式推,但是总是算错. 后来发现 ...

  5. pytorch基于卷积层通道剪枝的方法

    pytorch基于卷积层通道剪枝的方法 原文:https://blog.csdn.net/yyqq7226741/article/details/78301231 本文基于文章:Pruning Con ...

  6. 图解一维卷积层(PyTorch)

    图解一维卷积层(PyTorch) 在NLP中,我们需要对文本做embedding表示,那么embedding之后的文本做一维卷积运算的过程到底是什么样子的呢?我们给出下图加以说明

  7. Pytorch基础(四)—— 卷积层

    一.概念 卷积从数学的角度讲是一种矩阵的运算方法.我们可以用一个卷积核对一个矩阵进行卷积运算,具体运算过程图示可以见pytorch官网. 卷积运算按输入数据的通道数可分为单通道和多通道两种. 单通道是 ...

  8. pytorch —— nn网络层 - 卷积层

    目录 1.1d/2d/3d卷积 2.卷积-nn.Conv1d() 2.1 Conv1d的参数说明 2.2 例子说明 3.卷积-nn.Conv2d() 3.1 深入了解卷积层的参数 4.转置卷积-nn. ...

  9. 三分钟完全了解PyTorch中卷积层内部计算方法和权值初始值的来历,让你对模型有更深层次的理解

    首先先说明第一个答案,也就是PyTorch中卷积层的计算方法,其实这点很多人可能在书上已经看过图了,我只是用代码复现一遍 我们把所有变量都明确,首先是输入变量,我们设为2 * 2的全1矩阵,如下: 然 ...

最新文章

  1. 【例4-4】最小花费
  2. 在VMware Workstation中设置双网卡实现SSH使用固定IP登录并且在虚拟系统中任意访问Internet...
  3. Hadoop推测执行(以空间换取时间)
  4. 2019年3月前端面试题
  5. 转:高等数学、线性代数、概率论数理统计书籍推荐
  6. php asp.net 代码量少,.NET_asp.net 反射减少代码书写量, 复制代码 代码如下:public b - phpStudy...
  7. 在批处理文件中启动MediaPlayer播放制定文件
  8. OECP社区正式上线
  9. 输出流_关于输出字符流你真的懂了吗?
  10. 【Code-Snippet】ProgressBar
  11. 局域网中搜计算机无法访问,怎么找不到共享电脑,手把手教你局域网中共享电脑找不到怎么办...
  12. 【SLAM笔记】如何使用Eigen进行矩阵运算
  13. ps读写ddr3里面的数据 zynq_ZYNQ应该如何让PS端的opencv程序读取到ddr中的图像数据...
  14. workbench焊接实例_基于ANSYS Workbench平台和ANSYS经典界面的焊接仿真-工业电子-与非网...
  15. Java环境变量配置与adb环境变量配置
  16. 【ASO优化】手游9大ASO优化方法帮你获得巨量新增!
  17. 20120912新工作感想
  18. w8服务器dns修改,怎么修改DNS Win8修改DNS服务器地址的具体步骤图解
  19. css解决文字抖动问题
  20. Excel2010重复打印标题行

热门文章

  1. 标准文档流、脱离文档流及脱离文档流的3种方式
  2. c++中find() 函数与string::npos参数
  3. 网络营销实战密码:策略、技巧、案例——一本只看目录就可以达到目的的书
  4. 快乐数之数学规律解题
  5. idea中热部署插件JRebel的激活方式
  6. Python之异常处理语句
  7. git 删除远程仓库本地分支和删除远程分支,保留本地分支或者删除本地
  8. NRF52832之ESB功能与NRF24L01进行2.4G通信
  9. vs2015安装时无法选择安装路径解决办法
  10. 2021,CSS杀疯了