一、卷积

卷积有什么用?

通过卷积核的不同设置,使得每个输出通道可以识别特定的模式,比如识别边缘、锐化、模糊等操作。

核的参数怎么得到的?

学出来的,不是自己设置的。

卷积尺寸公式:

输出尺寸*=*[输入尺寸-kernel-size+2*padding+stride]/stride

填充

在输入周围添加行/列,来控制输出形状的减少量

步幅

每次滑动kernal窗口时的行/列的步长,可以成倍的减少输出形状

image-20250125203559067

注意:

1、第一个公式里的ph是要上下都加了行,所以要乘以二!!!

2、padding通常设置为k-1 (核-1)

问题

1、为什么通常用3x3或者5x5的卷积核呢?他们的视野不是很小吗?(更常用3x3,计算量更小)

多加几层卷积层,最后的到的层会涵盖初始层中很大范围的内容。

image-20250125210159175

多输入通道

image-20250126204241191

这样只能得到单输出的通道

如何得到多输出通道?

输入的三通道数据和多个卷积核进行卷积,得到多通道的输出。

image-20250126204931218

co表示卷积核的个数,ci表示卷积核的维度,第0维的卷积层和第0维的输入进行计算,第1维的卷积层和第1维的输入进行计算…,然后将同一位置不同层的计算结果相加,得到这一块的输出内容,再按此方法进行卷积操作得到第一维度的输出。使用其他的卷积核进行相同操作,最后得到多输出通道。

1x1 卷积层

image-20250126210139909

用于不同通道使用不同权重进行融合。

二、最大/平均池化

返回滑动窗口中的最大值/平均值

缓解卷积层对于位置的敏感性,通常放在卷积层之后。

pytorch中,如果不设置默认:池化窗口=步幅,就是保证窗口不重叠

为什么现在池化用的少了?

现在通常用一个卷积层+stride减少输出

三、LeNet

image-20250202195341765

如何检验层的尺寸有没有搭错:

image-20250202200046443

四、AlexNet

在LetNet基础上添加了一些层,效果更好

五、VGG块

将AlexNet中的多个卷积层封装成一个块,使用多个VGG块构建深度卷积神经网络,效果更好。

不同的卷积块个数和超参数可以得到不同复杂度的变种。

注:在VGG中,内部卷积层的个数n,通道m是超参数。

六、NiN

全连接层的问题:

卷积层后的得到第一个全连接层时的计算量会非常大容易过拟合

image-20250203204835160

NiN块

一个卷积层后跟两个全连接层

image-20250203204956898

为什么用的是两个1x1的卷积层?他们其实相当于没有将输入拍扁的全连接层

NiN架构

image-20250203205310762

总结

Nin块使用卷积层加两个1x1卷积层,后者对每个像素增加了非线性性。

Nin用全局平均池化层来替代VGG和AlexNet中的全连接层——不容易过拟合,更少的参数个数。

七、批量归一化 Batch Normalization

——加速收敛、网络训练速度

image-20250204164534195

BN层一般用于深层神经网络,浅层的效果不好。

解释

由于学习过程中会调整每个层的超参数,当调整前面的层时,会导致后面的层需要重新进行学习,进而导致最后得到的层很难收敛。所以学习率不能设置太高。

批量归一化将每一层的输出进行归一化,使对下一层的输出相似但不完全相同,这样后面的层就不需要改动太大。因此可以选择较大的学习率,加快了网络的训练。

后有论文指出它可能就是通过在每个小批量里加入噪音来控制模型的复杂度。

因此没必要跟丢弃法混合使用。

image-20250204165011101

分布归一化放在非线性激活前面!

需要训练的参数增加了γ和β,原来的偏置是定好的不需要学习。所以现在有三个参数需要学习。

调包实现

nn.BatchNorm2d(输入的通道数)

nn.BatchNorm1d(输入的通道数)

八、ResNet

image-20250204200225258

不断添加层数,得到的模型一定最优吗?

不一定。反而可能会越来越偏离最优函数。

残差块

image-20250204200355148

f(x)=x+g(x)

使得新的模型必须包含之前的模型,因此精度不可能变差。

  • 如果g(x)没什么用,那么系统后面给它的梯度会很小,它对最后的结果影响就很小了。

同时,残差块使得很深的网络更加容易训练。

这样加法的操作使得反向传播计算梯度时,即使g(x)的偏导很小,由于是加法,也可以求出x的偏导,那么f(x)得到的梯度就不至于消失。

解决了深层网络底层比较难以训练的问题。——底层拿到的梯度一般比较小。

九、数据增强

增加一个已有的数据集,使其有更多的多样性。

  • ​ 增加不同的背景噪音
  • ​ 改变图片的颜色和形状

常见增强方法

翻转

左右、上下翻转

但不是总是可行。比如建筑之类的翻转不太符合实际。但树叶什么的翻转没关系。

切割

从图片中切割一块,然后变形到固定形状

  • 随机高宽比(eg.[3/4,4/3])
  • 随机大小(eg.[8%,100%])
  • 随机位置

颜色

改变色调,饱和度,明亮度(当前的情况减少50%或增加50%的范围内)

其他

https://github.com/aleju/imgaug

十、微调 fine-tune

微调中的权重初始化

image-20250206203248814

源数据集远复杂于目标数据,通常微调的效果更好(速度更快、精度越高)。

  • 使用更小的学习率

  • 使用更少的数据迭代

1、重用分类器权重

源数据集可能也有目标数据中的部分标号,可以使用预训练好的模型分类器中对应标号对应的向量来做初始化。

2、固定一些层

  • 神经网络通常学习有层次的特征:
    • 低层次的特征更加通用
    • 高层次的特征更加与数据集有关
  • 可以固定底部一些层的参数,不参与更新。

十一、锚框

一类目标检测算法是基于锚框的

  • 提出多个被称为锚框的区域
  • 预测每个锚框里是否含有关注的物体
  • 如果是,预测从这个锚框到真实边缘框的偏移

IoU 交并比

image-20250208160454237 image-20250208160523457

赋予锚框标号

image-20250209105249553

第一步的意思就是使用锚框2去预测边缘框3。

一张图有多少个边缘框,就对应有多少个训练样本。

使用非极大值抑制(NMS)输出

  • 每个锚框预测一个边缘框
  • NMS可以合并相似的预测
    • 选中是非背景类的最大预测值
    • 去掉其他和它IoU值大于θ的预测
    • 重复上述过程知道所有预测要么被选中,要么被去掉
image-20250209105958709

十二、物体检测算法 R-CNN

兴趣区域(RoI)池化层

image-20250209163934488

给定一个锚框,均匀分割成n×m块,输出每块里的最大值

不管锚框多大,总是输出nm个值

强行将图像变成大小一样的。

Fast RCNN

  • 使用CNN对图片抽取特征
  • 再使用RoI池化层对每个锚框生成固定长度特征

在原始图片上搜索到锚框后,把锚框按照比例映射到经过CNN层的特征层。

image-20250209165216146

Faster R-CNN

image-20250209165440613

Mask R-CNN

如果有像素级别的标号,使用FCN来利用这些信息。

image-20250209170559072

总结

image-20250209171622411

十三、单发多框检测 SSD

生成锚框

image-20250209172045212

SSD模型

image-20250209172314880

十四、YOLO: you only look once

在SSD的基础上进行改进,避免大量SSD重叠。

image-20250209173141837

十五、语义分割

语义分割可以识别并理解图像中每一个像素的内容:其语义区域的标注和预测是像素级的。

即每一个像素都有其对应的类别。

列举RGB值和类名

1
2
3
4
5
6
7
8
9
10
11
12
13
#@save
VOC_COLORMAP = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0],
[0, 0, 128], [128, 0, 128], [0, 128, 128], [128, 128, 128],
[64, 0, 0], [192, 0, 0], [64, 128, 0], [192, 128, 0],
[64, 0, 128], [192, 0, 128], [64, 128, 128], [192, 128, 128],
[0, 64, 0], [128, 64, 0], [0, 192, 0], [128, 192, 0],
[0, 64, 128]]

#@save
VOC_CLASSES = ['background', 'aeroplane', 'bicycle', 'bird', 'boat',
'bottle', 'bus', 'car', 'cat', 'chair', 'cow',
'diningtable', 'dog', 'horse', 'motorbike', 'person',
'potted plant', 'sheep', 'sofa', 'train', 'tv/monitor']

构建从RGB到VOC类别索引的映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#@save
def voc_colormap2label():
"""构建从RGB到VOC类别索引的映射"""
colormap2label = torch.zeros(256 ** 3, dtype=torch.long)
for i, colormap in enumerate(VOC_COLORMAP):
colormap2label[
(colormap[0] * 256 + colormap[1]) * 256 + colormap[2]] = i
# 把RGB三通道的数值当做256进制的数(因为像素最多从0-255)每个像素值算出对应10进制数存入tensor 这样可以对应到每个像素所属类别。
# i表示这个颜色对应类别的序号
return colormap2label

#@save
def voc_label_indices(colormap, colormap2label):
"""将VOC标签中的RGB值映射到它们的类别索引"""
colormap = colormap.permute(1, 2, 0).numpy().astype('int32')
# 将输入的彩色标签图像的维度从(通道,高度,宽度)重排为(高度,宽度,通道),然后将其转换为NumPy数组,并将数据类型转换为32位整数,以便进行后续计算。
idx = ((colormap[:, :, 0] * 256 + colormap[:, :, 1]) * 256
+ colormap[:, :, 2]) # 计算RGB值对应的类别的索引
return colormap2label[idx] #返回对应类别的序号

十六、转置卷积

卷积不会增大输入的高宽,通常要么不变、要么减半。

而转置卷积则可以用来增大输入的高宽。

image-20250210202817711

1
2
3
4
5
6
7
8
X = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
trans_conv(X, K)
X, K = X.reshape(1, 1, 2, 2), K.reshape(1, 1, 2, 2)
#调用api实现转置卷积
tconv = nn.ConvTranspose2d(1, 1, kernel_size=2, bias=False) #输入通道数,输出通道数,核的大小,是否有偏移
tconv.weight.data = K
tconv(X)

填充、步幅和多通道

转置卷积的填充(padding)是加在输出上的。

如上图的转置卷积过程,如果padding=1,则最后的结果为4。(删除第一和最后的行和列)

image-20250210211025587

对于多个输入和输出通道,转置卷积与常规卷积以相同方式运作。
假设输入有$c_i$个通道,且转置卷积为每个输入通道分配了一个$k_h\times k_w$的卷积核张量。
当指定多个输出通道时,每个输出通道将有一个$c_i\times k_h\times k_w$的卷积核。

如果我们将$\mathsf{X}$代入卷积层$f$来输出$\mathsf{Y}=f(\mathsf{X})$,并创建一个与$f$具有相同的超参数、但输出通道数量是$\mathsf{X}$中通道数的转置卷积层$g$,那么$g(Y)$的形状将与$\mathsf{X}$相同。

转置卷积与卷积的转换

image-20250211172618374 image-20250211173143405

十七、全连接卷积神经网络 FCN

用转置卷积层来替换CNN最后的全连接层,从而实现每个像素的预测

image-20250211173942625

最后的通道数 = 类别数

十八、序列模型

时序模型中,当前数据和之间观察到的数据相关。

常见的两种方案

image-20250211211819095

image-20250211212120318

十九、注意力机制

卷积、全连接、池化层都只考虑不随意线索。

注意力机制则考虑随意线索

  • 随意线索被称之为查询(query)
  • 每个输入是一个值(value)和不随意线索(key)的对
  • 通过注意力池化层来有偏向性的选择某些输入

注意力机制的本质https://www.bilibili.com/video/BV1dt4y1J7ov/?share_source=copy_web&spm_id_from=333.788.comment.all.click&vd_source=c675206b339487e9755eec554de241a9

image-20250214104442014

非参的注意力池化层

image-20250214104642886

1、一般情况

image-20250214105230900

2、Nadaraya-Watson 核回归

image-20250214104915705

参数化的注意力机制

在之前的基础上引入可以学习的w

image-20250214105030923

注意力分数

image-20250214111827479

加性注意力 additive attention

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#@save
class AdditiveAttention(nn.Module):
"""加性注意力"""
def __init__(self, key_size, query_size, num_hiddens, dropout, **kwargs):
super(AdditiveAttention, self).__init__(**kwargs)
self.W_k = nn.Linear(key_size, num_hiddens, bias=False)
self.W_q = nn.Linear(query_size, num_hiddens, bias=False)
self.w_v = nn.Linear(num_hiddens, 1, bias=False)
self.dropout = nn.Dropout(dropout)

def forward(self, queries, keys, values, valid_lens):
queries, keys = self.W_q(queries), self.W_k(keys)
# 在维度扩展后,
# queries的形状:(batch_size,查询的个数,1,num_hidden)
# key的形状:(batch_size,1,“键-值”对的个数,num_hiddens)
# 使用广播方式进行求和 —— 广播规则:维度大小为1的轴会自动扩展以匹配另一张量的形状。
# 18行feature的形状:(batch_size,查询的个数,“键-值”对的个数,num_hiddens)
features = queries.unsqueeze(2) + keys.unsqueeze(1)
features = torch.tanh(features)
# self.w_v仅有一个输出,因此从形状中移除最后那个维度。
# scores的形状:(batch_size,查询的个数,“键-值”对的个数)
scores = self.w_v(features).squeeze(-1)
self.attention_weights = masked_softmax(scores, valid_lens) # 注意力权重
# values的形状:(batch_size,“键-值”对的个数,值的维度)
return torch.bmm(self.dropout(self.attention_weights), values) # 将注意力权重与值进行矩阵乘法

为什么要采用广播机制?

通过广播机制,一次性生成所有 (query, key) 对的组合特征,避免逐对计算的低效循环。

示例说明

假设:

  • 批量大小 batch_size=2
  • 查询数量 num_queries=3
  • 键值对数量 num_kv_pairs=4
  • 隐藏维度 num_hiddens=5

经过 unsqueeze 和广播后:

  • queries 形状:(2, 3, 1, 5)
  • keys 形状:(2, 1, 4, 5)
  • 相加结果 features 形状:(2, 3, 4, 5)

这表示:

  • 对于批量中的每个样本(2个样本),
  • 每个查询(3个查询)与每个键(4个键)都进行了逐元素相加,
  • 最终得到 3×4=12 个查询-键对的交互特征。

为什么要用masked_softmax?

在处理文本数据集时,为了提高计算效率,可能会采用填充的方式使每个文本序列具有相同的长度,便于以相同形状的小批量进行加载,因此可能会存在一些文本序列被填充了没有意义的特殊词源(比如词元)。

使用masked_softmax可以过滤掉超出指定范围的位置,不让填充的无意义内容影响结果。

缩放点积注意力

见书P290

自注意力

完全并行、最长序列为1、但对长序列计算复杂度高

李宏毅:https://www.bilibili.com/video/BV1v3411r78R?spm_id_from=333.788.videopod.episodes&vd_source=ff957cd8fbaeb55d52afc75fbcc87dfd&p=2

image-20250216210649488

一、如何得到b1

image-20250216210602641

二、矩阵表示

1整体理解

image-20250216212359480

2具体表示

image-20250216211942646

image-20250216212118247

三、位置编码

在输入中加入位置信息

image-20250216214949465

二十、编码器-解码器

编码器处理输入,解码器生成输出(其实就是把功能集成到一起,然后起了个新名字)

image-20250217200853436

二十一、Transformer

image-20250217201023952

多头注意力

image-20250217201206994

每个注意力池化层都是不同的weight

有掩码的多头注意力

解码器对序列中一个元素输出时,不应该考虑该元素之后的元素。

通过掩码实现

  • 计算xi的输出时,假装当前序列长度为i
image-20250217201502438

基于位置的前馈网络

image-20250217201606217

n是序列的长度,不同数据n会变,不能作为特征处理,即n的变化不能影响模型。

层归一化

image-20250217201854048

信息传递

image-20250217202324024

预测

image-20250217202600944

总结

  • Transformer是一个纯使用注意力的编码-阶码器
  • 编码器和解码器都有n个transformer块
  • 每个块里使用多头(自)注意力、基于位置的前馈网络、 层归一化