深度学习知识点汇总

深度学习知识点汇总

深度学习的57个专业术语

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import torch
import torch.nn as nn

# 定义模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(input_size, hidden_units)
self.dropout = nn.Dropout(dropout_rate)
self.fc2 = nn.Linear(hidden_units, num_classes)

def forward(self, x):
x = torch.relu(self.fc1(x))
x = self.dropout(x)
x = self.fc2(x)
return x

# 创建模型实例
model = Net()

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

# 训练模型
for epoch in range(num_epochs):
for i, (images, labels) in enumerate(train_loader):
images = images.reshape(-1, input_size)

# 前向传播
outputs = model(images)
loss = criterion(outputs, labels)

# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()

# 打印训练信息
if (i+1) % display_step == 0:
print('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'
.format(epoch+1, num_epochs, i+1, total_steps, loss.item()))

# 在测试集上评估模型
with torch.no_grad():
correct = 0
total = 0
for images, labels in test_loader:
images = images.reshape(-1, input_size)
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum()

print('Test Accuracy: {}%'.format(100 * correct / total))

12.1

过拟合和欠拟合(Overfitting and underfitting)

过拟合和欠拟合是导致模型泛化能力不高的两种常见原因,都是模型学习能力与数据复杂度之间失配的结果。
“欠拟合”常常在模型学习能力较弱,而数据复杂度较高的情况出现,此时模型由于学习能力不足,无法学习到数据集中的“一般规律”,因而导致泛化能力弱。
“过拟合”常常在模型学习能力过强的情况中出现,此时的模型学习能力太强,以至于将训练集单个样本自身的特点都能捕捉到,并将其认为是“一般规律”,同样这种情况也会导致模型泛化能力下降。

Overfitting

过拟合(over-fitting)也称为过学习,它的直观表现是算法在训练集上表现好,但在测试集上表现不好,泛化性能差
cause

  • 训练集的数据太少或者缺乏代表性;
  • 训练集样本存在的噪音干扰过大,导致模型拟合了噪音的特征,反而忽略了真实的输入输出间的关系;
  • 参数太多,模型复杂度过高;

method

1.增加数据量

  • 从数据源头获取更多数据;
  • 通过数据增强对数据进行扩充:对图像进行翻转、裁剪、缩放、平移、添加噪声等。

2.正则化
在进行目标函数或代价函数(损失函数)优化时,在函数后面加上一个正则项,一般有L1正则、L2正则等。

  • L1正则化: L1正则化是通过在目标函数中加入L1范数惩罚项来实现的。L1范数是指权重向量W中的各个元素绝对值之和,因此L1正则化的目的是使模型参数尽可能地稀疏。L1正则化可以促使模型参数向零值收缩,进而减少特征的数量。
  • L2正则化: L2正则化是通过在目标函数中加入L2范数惩罚项来实现的。L2范数是指权重向量W中的各个元素的平方和开根号,因此L2正则化的目的是通过约束模型参数的平方和,使得它们的值不会过大。L2正则化可以帮助避免模型的权值过拟合,并使得模型更具有鲁棒性和泛化能力。
1
2
3
4
5
# 添加L2正则化项
l2_reg = torch.tensor(0.) # 创建一个初始值为零的 torch.Tensor 对象,用于累加模型参数的 L2 范数。
for param in model.parameters():
l2_reg += torch.norm(param, 2)
loss += l2_penalty * l2_reg # L2 正则化的惩罚系数(penalty coefficient),用于控制正则化的强度。它是一个超参数,需要根据具体问题进行调整(交叉验证)。

区别: L1正则化减少的是一个常量,L2正则化减少的是权重的固定比例;使用L1可以得到稀疏的权值,使用L2可以得到平滑的权值;实践中L2正则化通常优于L1正则化。

3.Dropout
Dropout 是一种常用的正则化技术,用于减少深度神经网络的过拟合现象。Dropout 在训练过程中随机地丢弃一部分神经元的输出,从而强制模型去学习其他特征的表示。

self.dropout = nn.Dropout(dropout_rate)

具体来说,Dropout 在前向传播的过程中,以一定的概率 p(通常设置为0.5)将某个神经元的输出设为0,即丢弃该神经元。这样做的结果是,每个神经元在训练过程中都有一定概率暂时被“关闭”,从而迫使网络去考虑其他神经元的贡献,减少了对特定神经元的依赖性。同时,在前向传播过程中,通过保留每个神经元输出的比例,可以确保网络的总体期望值不变。

12.2

Triplet Loss 和 Center Loss

https://blog.csdn.net/weixin_40671425/article/details/98068190

12.2

https://zhuanlan.zhihu.com/p/438085414

tensor

Tensor(张量)是一个多维数组,它是深度学习中最基本的数据结构之一,也是基于计算图的深度学习框架的核心组成部分。Tensor 可以存储和表示任意维度的数据,支持各种数值和数据类型,并提供了类似于 numpy 的数据操作接口,例如加、减、乘、除、运算、矩阵乘法、转置等。在深度学习中,我们使用 Tensor 来存储训练样本和模型参数,并对它们进行线性和非线性的运算。

Tensor 的维度通常被称作“阶”,例如,阶为 0 的 Tensor 又被称作“标量”(scalar),表示一个单独的数值;阶为 1 的 Tensor 又被称作“向量”(vector),表示一列数值;阶为 2 的 Tensor 又被称作“矩阵”(matrix),表示一个二维的表格。在深度学习中,我们通常会使用阶数更高的 Tensor,例如 3 阶、4 阶或更高阶的 Tensor,以表示更复杂的数据结构,如图像、视频或音频数据等。

1.张量的创建

1.1 通过列表或者元组

1
2
3
t = torch([1,2]) / t = torch((1,2))
print(t)
# tensor([1, 2])

1.2 通过numpy创建

1
2
3
4
5
import numpy as np
n = np.array([1,2])
t = torch.tensor(n)
print(t)
# tensor([1, 2])

1.3 tensor-type and convert

type()不能识别出Tensor内部的数据类型,只能识别出变量的基本类型是Tensor,而dtype方法可以识别出变量具体为哪种类型的Tensor。
可以使用.float()、.int()等方法对张量类型进行转化。

1
2
3
4
5
6
7
8
9
10
11
12
13
i = torch.tensor([1, 2])
f = torch.tensor([1.0, 2.0])
print(type(i), i.dtype, sep = ' , ')
print(type(f), f.dtype, sep = ' , ')
# <class 'torch.Tensor'> , torch.int64
# <class 'torch.Tensor'> , torch.float32

t = torch.tensor([1, 2])
f = t.float()
print(f)
print(t) # 并不会改变原来t的数据类型
# tensor([1., 2.])
# tensor([1, 2])

tensor—shape

张量的维度中,我们使用的张量如下:

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
26
27
28
29
30
31
32
33
34
35
36
# 一维向量
t1 = torch.tensor((1, 2))
# 二维向量
t2 = torch.tensor([[1, 2, 3], [4, 5, 6]])
# 三维向量
t3 = torch.tensor([[[1, 2], [3, 4]],[[5, 6], [7, 8]]])

# ndim查看张量维度
print(t1.ndim, t2.ndim, t3.ndim, sep = ', ')
# 1, 2, 3
# t1为1维向量
# t2为2维矩阵
# t3为3维张量

# shape&size查看向量的形状
print(t1.shape, t2.shape, t3.shape, sep = ', ')
# torch.Size([2]), torch.Size([2, 3]), torch.Size([2, 2, 2])

print(t1.size(), t2.size(), t3.size(), sep = ', ')
# torch.Size([2]), torch.Size([2, 3]), torch.Size([2, 2, 2])

# numel查看张量中的元素个数
print(t1.numel(), t2.numel(), t3.numel(), sep = ', ')
# 2, 6, 8
# t1向量中共有2个元素
# t2矩阵中共有6个元素
# t3张量中共有8个元素

# flatten将任意维度张量转为一维张量
t2.flatten()
# tensor([1, 2, 3, 4, 5, 6])

t3.flatten()
# tensor([1, 2, 3, 4, 5, 6, 7, 8])


  • t1向量torch.Size([2])的理解:向量的形状是1行2列。
  • t2矩阵torch.Size([2, 3])的理解:二维矩阵的形状是2行3列。
  • t3矩阵torch.Size([2, 2, 2])的理解:包含两个二维矩阵,每个二维矩阵的形状是2行2列。

reshape任意变形

形变维度的乘积需要等于张量元素的个数。

1
2
3
4
5
6
7
# 将`t3`变成2×4的矩阵
t3.reshape(2, 4)
#tensor([[1, 2, 3, 4],[5, 6, 7, 8]])

# 将`t3`变成1×4×2的矩阵
t3.reshape(1, 4, 2)
# tensor([[[1, 2], [3, 4], [5, 6], [7, 8]]])

squeeze&unsqueeze

  • squeeze的作用是压缩张量,去掉维数为1位置的维度
  • unsqueeze的作用是解压张量,给指定位置加上维数为一的维度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 将t3的维度变为2×1×4
t_214 = t3.reshape(2, 1, 4)
print(t_214)
# tensor([[[1, 2, 3, 4]], [[5, 6, 7, 8]]])

# 使用squeeze将其变成2×4,去掉维度为1位置的维度
t_24 = t_214.squeeze(1)
print(t_24)
# tensor([[1, 2, 3, 4], [5, 6, 7, 8]])

# 将2×4的维度再转换成2×1×4,在第二个维度上加一维
# 索引是从0开始的。参数0代表第一维,参数1代表第二维,以此类推
print(t_24.unsqueeze(1))
tensor([[[1, 2, 3, 4]], [[5, 6, 7, 8]]])

tensor ——> value

1
2
3
4
5
n = torch.tensor(1)
print(n) # tensor(1)

# 使用.item()方法将张量转为python中的数值
n.item() # 1

张量的索引

张量是有序序列,我们可以根据每个元素在系统内的顺序位置,来找出特定的元素,也就是索引。

一维张量索引与Python中的索引一样是是从左到右,从0开始的,遵循格式为[start: end: step]。

张量的合并与分割

当对一个张量进行切割时,返回的是原始张量的一个视图(view)或子集,而不是创建一个新的张量。这意味着切片返回的是原始张量的一个引用,并与原始张量共享数据存储,所以在修改切片返回的张量时,会同时修改原始张量中相应的元素。 需要注意的是,如果我们希望创建一个拷贝而非共享内存的切片,可以使用 .copy() 方法,这样操作切片将不会对原始张量产生影响。

张量的分割 chunk & split

chunk(tensor, chunks, dim)能够按照某个维度(dim)对张量进行均匀切分(chunks),并且返回结果是原张量的视图。

张量的合并 cat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
a = torch.zeros(2, 3)
# tensor([[0., 0., 0.],
# [0., 0., 0.]])

b = torch.ones(2, 3)
# tensor([[1., 1., 1.],
# [1., 1., 1.]])


因为在张量a与b中,shape的第一个位置是代表向量维度,所以当dim取0时,就是将向量进行合并,向量中的标量数不变:
torch.cat([a, b], dim = 0)
# tensor([[0., 0., 0.],
# [0., 0., 0.],
# [1., 1., 1.],
# [1., 1., 1.]])

当dim取1时,shape的第二个位置是代表列,即标量数,就是在列上(标量维度)进行拼接,行数(向量数)不变:
torch.cat([a, b], dim = 1)
# tensor([[0., 0., 0., 1., 1., 1.],
## [0., 0., 0., 1., 1., 1.]])

张量的堆叠 stack

和拼接不同,堆叠不是将元素拆分重装,而是将各参与堆叠的对象分装到一个更高维度的张量里。
和 cat 的区别:拼接之后维度不变,堆叠之后维度升高。拼接是把一个个元素单独提取出来之后再放到二维张量里,而堆叠则是直接将两个二维向量封装到一个三维张量中。因此,堆叠的要求更高,参与堆叠的张量必须形状完全相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a = torch.zeros(2, 3)
# tensor([[0., 0., 0.],
# [0., 0., 0.]])

b = torch.ones(2, 3)
# tensor([[1., 1., 1.],
# [1., 1., 1.]])

torch.stack([a, b], dim = 0)
# tensor([[[0., 0., 0.],
# [0., 0., 0.]],
# [[1., 1., 1.],
# [1., 1., 1.]]])

torch.stack([a, b], dim = 0).shape
# torch.Size([2, 2, 3])

12.3

注意力机制

通道注意力(Channel Attention),空间注意力(Spatial Attention),分支注意力(Branch Attention),自注意力(Self Attention)和交叉注意力(Cross Attention)

12.8

vision transformer

grad-cam

Vit + Grad-Cam

https://zhuanlan.zhihu.com/p/640450435
Grad-CAM 对 ViT 的输出进行可视化的原理是利用 ViT 的最后一个注意力块的输出和梯度,计算出每个 token 对分类结果的贡献度,然后将这些贡献度映射回原始图像的空间位置,形成一张热力图。


深度学习知识点汇总
https://cs-lb.github.io/2024/04/14/深度学习/深度学习知识点汇总/
作者
Liu Bo
发布于
2024年4月14日
许可协议