1 bs
小:batch数太小,而类别又比较多的时候,真的可能会导致loss函数震荡而不收敛
大:局部最小值,处理相同的数据量的速度越快,Batch_Size 增大到某个时候,达到时间上的最优
2 BN层
- 加快网络的训练和收敛的速度
- 控制梯度爆炸防止梯度消失
- 防止过拟合
当然,如果是小批量输入数据,即每次输入原数据的一部分时,经过多轮epoch迭代,BN最终也将累计记录到整体均值和方差。
对照这个就可以了。
我们可以清楚的看到,BN层对更加复杂模型的优化效果更好。换而言之,越复杂的模型对于梯度不平稳的问题就越明显,因此BN层在解决该问题后模型效果提升就越明显。
3 w的初始化和激活函数作用
Pytorch权重初始化方法——Kaiming、Xavier_kaiming初始化_劳塔罗爆射破门的博客-CSDN博客
Mish激活函数主要有一下四个特点:无上界、无下界、光滑、非单调。这四个特性提高了函数的性能。无上限:它可以防止网络饱和,即梯度消失。有下界:提高网络的正则化效果。平滑:首先,与ReLU相比,在0值点连续可以减少一些不可预测的问题。其次,它可以使网络更容易优化,提高泛化性能,一些较小的负输入可以保留为负输出,以提高网络的可解释性和梯度流。
pytorch没有现成的包装
sigmoid——梯度消失(w=0)——Xavier有意义+BN算法
tanh—— 梯度爆炸(w>0)——w>1; 方法:xavier有意义+BN算法
relu ——死点问题 ,x<0为0 (降低学习率,Kaiming方法)——学习率更小,Kaiming 方法
4 学习率调节
5 conv2d
CV【2】:卷积与Conv2d_conv2d卷积核_zzzyzh的博客-CSDN博客
公式
边缘检测是卷积操作的一个常见应用,我们所使用的权重矩阵其实是纵向的索贝尔算子(Sobel
Operator),用于检测纵向的边缘,我们也可以使用横向的索贝尔算子,以及拉普拉斯算子来检测边缘。在OpenCV当中我们可以很容易地实现这个操作:
K的大小
卷积核一般都是奇数3*3/5*5/7*7 cv卷积核一般比较小,
stride
通常是1-3
特征图的尺寸大小
特征图的尺寸非常重要,它既不能太小,也不能太大。如果特征图太小,
就可能缺乏可以提取的信息,进一步缩小的可能性就更低,网络深度就会受限制。如果特征图太大,每个卷积核需要扫描的次数就越多,所需要的卷积操作就会越多,影响整体计算
padding
还有vaild直接不填充了
maxpool+avgpool
注意是步长可能相似不意味着卷积核
池化层不随着算法进行进步
6 Dropout2d与BatchNorm2d
7 LeNet5 ——定义框架
不能改变特征尺寸,容易报错大
2个卷积和平均池化+1个fc+softmax ,加入得是tanh,除此以外没有别的relu,BN
(conv+tanh+avg)*2 +(fc+tanh)+softmax
8 AlexNet——小卷积核
经验:
1 卷积核很小的情况 会增大特征。(卷积核不适应可以换)
2 步长很大,会让特征变少。但速度很快。
3 增加通道数目 会让特征变多。
思路
1 (小卷积(会让特征图下降更慢,可以用不同网络提取信息),核搭配大通道) 小而深——小卷积,多通道,大步长。
2 大尺寸先变成小尺寸(227*227-32*32) 加深深度,(减少尺寸,增大深度)
3 relu函数
4 加入BN层
5 增强数据集
6 训练使用GPU
网络结构
(conv+relu+pool)x2+(conv+relu)x3+pool+(fc+relu) x2 +softmax
该有的都有的,此外加入一个
9 VGG16——加深层数
引言:如何减小特征图尺寸呢? 1、padding+stride进行的缩短2/4个 2 特征图不变 maxpool缩小
思想:使用多个连续且保持尺寸不变的卷积核,卷积层加大深度,maxpool进行将尺寸减半
共同点:conv 和fc 后面都有relu
补充知识点
感受野与加层
为什么加深层可以效果更好:更大感受野+复杂的非线性函数(池化层放大感受野的
感受野:1 聚焦于中间位置的图像 2 深度越大,感受野越大,放大感受野的效率更高
如何提高感受野:1 加大深度 2利用池化 3 膨胀卷积
平移不变性
大部分神经网络具有一定的平移不变性。
1、CNN的平移不变性只能够应对“微小的平移”,当物体横向或纵向平移的像素过多时,CNN的平移不变性会衰减
2、卷积+池化层的叠加可以增强CNN的平移不变性(更深的网络拥有更强的平移不变性),同时增强模型的鲁棒性
参数量影响
卷积层
目标:相同的预测效果下,参数量越小越好
参数量大小:(卷积核高*宽*输入通道数)*输出通道数+输出通道数
大尺寸卷积核vs小尺寸卷积核
1*1卷积核:然而,由于1x1卷积核可以在不增加也不减少信息的情况下维持特征图的尺寸,加深度
分组卷积
深度卷积:
全连接层
作用:1分类器,进行分类2 作为整合信息的工具,将特征图中的信息进行整合
全卷积层1*1代替线性层
解放了输入层对图像尺寸的限制 实际就是fc由于maxpool替换了
10 NIN----全卷积网络部署连接层
主要原因看一下补充知识点
1 全连接层 2通道是先增大后来一点点减小
11 GoogleLeNet——并联机构
加深网络的结构的inception块
1 采用了多种卷积核确保各种类型和层次得信息提取出来
2 并联效率更高,使得连接层得效率更高
3 大量使用1*1 卷积,加层,扩大感受野。
多层次的读取信息——辅助信息
网络图:
12 Resnet
残差块:残差单元,残差网络中,我们将众多残差单元与普通卷积层串联——在浅层网络后堆叠某种结构以加深度。
残差单元的比较
1 残差单元实现了0负担增加深度,不复杂
2 残差快容易训练保持必要精度
几个问题:
1 padding :例如每一层的padding和stride。幸运的是,我们只有1x1和3x3两种卷积核,为了保持特征图的尺寸不变,1x1卷积核搭配的padding都为0,3x3卷积核搭配的padding都为1。
2 stride :这说明5次降维任务中的其他4次都是由步长为2的卷积层来完成的
3 跳跃连接上的卷积层 :因此,每当卷积层缩小特征图尺寸时,也需要在跳跃连接上加入核为1x1、步长为2的卷积层用于缩小原始特征图的尺寸。特别的,我们使用虚线来表示含有1x1卷积层的跳跃连接。
4 BN与relu位置:主题是conv+BN+RELU 残差值得是加一起后relu。对于两种块而言,最后一个卷积层后能够作用BN层
5 参数初始化在哪里实现
初始化:是令残差单元或瓶颈架构尽量与恒等函数相似
对于第一层来说残差支流不需要进行卷积
middle指的是中间得一块,128,输入in指的是256 输出的是512
13 优化算法
1 adaGrad
定义:使用每个维度上权重梯度的大小来自适应调整学习,避免学习率难以适应所有的维度问题
公式:
缺陷:
2 RMSprop
借鉴了BN层得动量法
3 Adama
14 Gan网络介绍
1 GAN
定义
交叉熵
生成图像越准确说明越好。此事判别器loss不就越大
# 两个线性层改变1进入1输出求出概率
class Discriminator(nn.Module):
def __init__(self,in_features):
"""in_features : 真实数据的维度、同时也是生成的假数据的维度,对于普通神经网络而言就是特征数量"""
super().__init__()
self.disc = nn.Sequential(nn.Linear(in_features,128)
#,nn.BatchNorm1d(128)
,nn.LeakyReLU(0.1) #由于生成对抗网络的损失非常容易梯度消失,因此使用LeakyReLU
,nn.Linear(128,1)
,nn.Sigmoid()
)
def forward(self,data):
"""输入的data可以是真实数据时,Disc输出dx。输入的data是gz时,Disc输出dgz"""
return self.disc(data)
# 两个线性层
class Generator(nn.Module):
def __init__(self,in_features,out_features):
"""
in_features:生成器的in_features,一般输入z的维度z_dim,该值可自定义
out_features:生成器的out_features,需要与真实数据的维度一致
"""
super().__init__()
self.gen = nn.Sequential(nn.Linear(in_features,256)
#,nn.BatchNorm1d(256)
,nn.LeakyReLU(0.1)
,nn.Linear(256,out_features) # 得出out_feaure 函数
,nn.Tanh() #用于归一化数据 tanh对抗函数里面这个
)
def forward(self,z):
gz = self.gen(z)
return gz
#检测生成器、判别器能否顺利跑通
#假设真实数据结构为28*28*1 = 784(真实数据是784特征)
#输入噪声
z = torch.ones((10,64))
gen = Generator(64,784)
gen(z).shape #生成数据
torch.Size([10, 784])
disc = Discriminator(784)
disc(gen(z)).shape #输出唯一值概率看输入的是什么值
torch.Size([10, 1])
损失函数
for epoch in range(num_epochs):
# x特征矩阵,y(label不使用)
for batch_idx, (x,_) in enumerate(dataloader):
# 放到设备上去cpu(gpu)
x = x.view(-1,784).to(device)
batch_size = x.shape[0]
############################
# (1) 判别器的反向传播:最小化 -[logD(x) + log(1 - D(G(z)))]
############################
# -logdx
# 生成需要输入ceriterion 的真实标签1与预测概率
dx = disc(x).view(-1)#放入判别器
loss_real = criterion(dx,torch.ones_like(dx))
loss_real.backward()
# 计算所有真实数据的损失均值
D_x = dx.mean().item()
# -log(1-dgz)
# 生成需要输入ceriterion 的真实标签0与预测概率
# 因此噪声z的样本量必须与真实数据一样——batch_size,z_dim指的是每个样本噪音的个数
noise = torch.randn((batch_size,z_dim)).to(device)
gz = gen(noise)
dgz1 = disc(gz.detach())
# 计算所有的加上数据上的损失函数
loss_fake = criterion(dgz1,torch.zeros_like(dgz1))
loss_fake.backward()
D_G_z1 = dgz1.mean().item()
#计算errorD
errorD = (loss_real + loss_fake)/2
#分别进行迭代 判别器迭代,不设计原始和生成器
optim_disc.step()
disc.zero_grad()
############################
# (2) 生成器的反向传播:最小化 -log(D(G(z)))
############################
#生成需要输入criterion的真实标签1与预测概率gdz
#注意,由于在此时判别器上的权重已经被更新过了,所以dgz的值会变化,需要重新生成
# 判别器通过虚线进行反向传播
dgz2 = disc(gz)
#计算errorG
errorG = criterion(dgz2,torch.ones_like(dgz2))
errorG.backward() #反向传播
optim_gen.step() #更新生成器上的权重
gen.zero_grad() #清零生成器更新后梯度
D_G_z2 = dgz2.mean().item()
#监控训练进度
if batch_idx % 500 == 0 or batch_idx == 0:
print('[%d/%d][%d/%d]\tLoss_D: %.4f\tLoss_G: %.4f\tD(x): %.4f\tD(G(z)): %.4f / %.4f' %
(epoch+1, num_epochs, batch_idx, len(dataloader),errorD.item(), errorG.item(), D_x, D_G_z1, D_G_z2))
#保存errorG和errorD,以便后续绘图用
G_losses.append(errorG.item())
D_real_loss.append(loss_real.item())
D_fake_loss.append(loss_fake.item())
D_losses.append(errorD.item())
#将固定噪音fixed_noise输入生成器,查看输出的结果变化
if (iters % 500 == 0) or ((epoch == num_epochs-1) and (batch_idx == len(dataloader)-1)):
with torch.no_grad():
fake = gen(fixed_noise).cpu().detach()
print("fake data saved")
img_list.append(fake.view(-1,1,28,28))
iters += 1
损失函数三个:
判别器:loss_real = criterion(dx,torch.ones_like(dx)) + loss_fake
loss_fake=criterion(dgz1,torch.zeros_like(dgz1)) dgz1指的是生成的假
生成器: errorG = criterion(dgz2,torch.ones_like(dgz2))
2 DCGan
反卷积与转置卷积
卷积运算的逆运算被称为反卷积(Deconvolution),反卷积是一种能够将某一卷积核的缩小效果完全逆转的运算,这种完全逆转可以将被卷积之前的图像像素极大程度地复原、甚至生成超越原始图像的图像,因此反卷积常被用于提升图像像素、为影像上色等实践领域。
相比之下,转置卷积只能够将图像恢复到被卷积之前的尺寸(即恢复空间信息),但不能复原被卷积之前的图像像素信息、甚至还会打乱图像中不同维度的信息、让通道信息混杂在一起,这就非常适合被用于从无到有生成数据。
相当于把基本Gan网络换成了DCGan
#实现DCGAN中的discriminator 3的卷积
def BasicConv2d(in_channels,out_channels,ks,s,p):
return nn.Sequential(nn.Conv2d(in_channels,out_channels,ks,s,p,bias=False)
,nn.BatchNorm2d(out_channels)
,nn.LeakyReLU(0.2,inplace=True))
class DCDisc(nn.Module):
def __init__(self):
super(DCDisc,self).__init__()
self.main = nn.Sequential(BasicConv2d(3,128,3,2,1)
,BasicConv2d(128,256,3,2,1)
,BasicConv2d(256,512,3,2,1)
,BasicConv2d(512,1024,3,2,1)
,nn.Conv2d(1024,1,3,2,0) # 320 可以按照以前的结构改
,nn.Sigmoid() # 二分类,多分类的话就是softmax
)
def forward(self,gz):
return self.main(gz)
# 转置卷积层
def BasicTransConv2d(in_channels,out_channels,ks,s,p):
return nn.Sequential(nn.ConvTranspose2d(in_channels,out_channels,ks,s,p,bias=False)
,nn.BatchNorm2d(out_channels)
,nn.ReLU(True))
#实现DCGAN中的GENERATOR 4的卷积
class DCGen(nn.Module):
def __init__(self):
super(DCGen, self).__init__()
self.main = nn.Sequential(BasicTransConv2d(100,1024,4,1,0)
,BasicTransConv2d(1024,512,4,2,1)
,BasicTransConv2d(512,256,4,2,1)
,BasicTransConv2d(256,128,4,2,1)
,nn.ConvTranspose2d(128,3,4,2,1)
,nn.Tanh()
)
def forward(self,z):
return self.main(z)
3 cGan 条件Gan网络
CGAN理论讲解及代码实现_cgan代码_无咎.lsy的博客-CSDN博客
代码原理:
代码解析:
#cGAN中的生成器
class cGAN_gen(nn.Module):
def __init__(self):
super().__init__()
self.label_upsample = nn.Sequential(nn.Embedding(10, 50)
,nn.Linear(50,49)
,nn.ReLU(inplace=True)
)
self.noise_upsample = nn.Sequential(nn.Linear(100,6272)
,nn.LeakyReLU(0.2,True)
)
self.main = nn.Sequential(nn.ConvTranspose2d(129,128,4,2,1) #这里使用的是能够使
,nn.LeakyReLU(0.2,True)
,nn.ConvTranspose2d(128,128,4,2,1)
,nn.LeakyReLU(0.2,True)
,nn.Conv2d(128,1,3,1,1) #卷积层作为最后的结尾层,最后输出图像尺寸为28x28
)
def forward(self,label,noise): #标签在前,噪音在后
noise = self.noise_upsample(noise)
noise = noise.view(-1,128,7,7)
label = self.label_upsample(label)
label = label.view(-1,1,7,7)
inputs = torch.cat((noise,label),dim=1)
fakedata = self.main(inputs)
return fakedata
判别器
#DCGAN中的判别器
class cGAN_disc(nn.Module):
def __init__(self):
super().__init__()
self.label_embedding = nn.Sequential(nn.Embedding(10,50)
,nn.Linear(50,784)
,nn.ReLU(inplace=True) #在架构图上这里没有激活函数
)
self.main = nn.Sequential(nn.Conv2d(2,128,3,2,1)
,nn.LeakyReLU(0.2,inplace=True)
,nn.Conv2d(128,128,3,2,1)
,nn.LeakyReLU(0.2,inplace=True)
) #由于Fashion-MNIST图像较小,因此在这里使用的卷积层也很少
self.output_ = nn.Sequential(nn.Dropout(0.2)
,nn.Linear(128*7*7,1))
def forward(self,label,realdata): #标签在前,数据在后
label = self.label_embedding(label)
label = label.view(-1,1,28,28)
inputs = torch.cat((realdata,label),dim=1)
features = self.main(inputs)
features = features.view(-1,128*7*7)
outputs = self.output_(features)
return outputs
4 infoGan
5 BIGGan
6 自编码器
1 稀疏自编码器
会舍弃一些的信息神经元
2 变分自动编码器
具体步骤
15 Transformer
1 NLP里面得Transformer
自注意力机制(Self-Attention)_Michael_Lzy的博客-CSDN博客
全网最通俗易懂的 Self-Attention自注意力机制 讲解_self attention机制-CSDN博客
史上最小白之Transformer详解_transformer最小白-CSDN博客
transform 词向量编码——onehot word2vec
位置编码——正余弦位置编码,正弦余弦函数生成
transformer位置信息:Transformer使用的是正余弦位置编码。位置编码通过使用不同频率的正弦、余弦函数生成,然后和对应的位置的词向量相加,位置向量维度必须和词向量的维度一致
只能进行相加,拼接的情况会使得数据量过大
mask:
1.padding mask:因为每个批次输入序列长度是不一样的也就是说,我们要对输入序列进行对齐。具体来说,就是给在较短的序列后面填充 0。但是如果输入的序列太长,则是截取左边的内容,把多余的直接舍弃
2 sequence mask
sequence mask 是为了使得 decoder 不能看见未来的信息。这在训练的时候有效,因为训练的时候每次我们是将target数据完整输入进decoder中,预测时不需要,预测的时候我们只能得到前一时刻预测出的输出
为什么会存在两层mutitransformers
跟我一样的牛角尖型选手可能又要发问啦,为啥Decoder中要搞两个Multi-Head Attention呢?
我个人理解是第一个Masked Multi-Head Attention是为了得到之前已经预测输出的信息,相当于记录当前时刻的输入之间的信息的意思。第二个Multi-Head Attention是为了通过当前输入的信息得到下一时刻的信息,也就是输出的信息,是为了表示当前的输入与经过encoder提取过的特征向量之间的关系来预测输出。
2 VIT
ViT (Visual Transformer)--CSDN博客
TNT
输入图像
总体上Dropout(下面) 到最后的LayerNorm 里面的是LayerNorm 到Dropout,里面是multi-head/MLP
3 Swin Transformer
Swin-Transformer详解_swin transformer-CSDN博客
为什么引入swin
1 双模太差异太大了 密集程度什么的
2 图像是高分辨率图像,不能进行识别;
整体框架
【深度学习】详解 Swin Transformer (SwinT)-CSDN博客
patch partion 指的是conv原图像输入进去经过卷积得到[B, C, H, W],然后 flatten: [B, C, H, W] -> [B, C, HW]
linear embing——Layernorm 指的是直接就是LN
对于SWIN
class SwinTransformerBlock(nn.Module):
r""" Swin Transformer Block.
Args:
dim (int): Number of input channels.
num_heads (int): Number of attention heads.
window_size (int): Window size.
shift_size (int): Shift size for SW-MSA.
mlp_ratio (float): Ratio of mlp hidden dim to embedding dim.
qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True
drop (float, optional): Dropout rate. Default: 0.0
attn_drop (float, optional): Attention dropout rate. Default: 0.0
drop_path (float, optional): Stochastic depth rate. Default: 0.0
act_layer (nn.Module, optional): Activation layer. Default: nn.GELU
norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm
"""
# 与Vit的block结构是相同的
def __init__(self, dim, num_heads, window_size=7, shift_size=0,
mlp_ratio=4., qkv_bias=True, drop=0., attn_drop=0., drop_path=0.,
act_layer=nn.GELU, norm_layer=nn.LayerNorm):
super().__init__()
self.dim = dim
self.num_heads = num_heads
self.window_size = window_size
self.shift_size = shift_size
self.mlp_ratio = mlp_ratio
assert 0 <= self.shift_size < self.window_size, "shift_size must in 0-window_size"
self.norm1 = norm_layer(dim)
self.attn = WindowAttention(
dim, window_size=(self.window_size, self.window_size), num_heads=num_heads, qkv_bias=qkv_bias,
attn_drop=attn_drop, proj_drop=drop)
self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
self.norm2 = norm_layer(dim)
mlp_hidden_dim = int(dim * mlp_ratio)
self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
def forward(self, x, attn_mask):
# x(B,L,C),因此需要记录h和w
H, W = self.H, self.W
B, L, C = x.shape
assert L == H * W, "input feature has wrong size"
# 残差网络
shortcut = x
x = self.norm1(x)
x = x.view(B, H, W, C)
#图像填充(B, H, W, C)微调尺寸
# pad feature maps to multiples of window size
# 把feature map给pad到window size的整数倍
pad_l = pad_t = 0
pad_r = (self.window_size - W % self.window_size) % self.window_size
pad_b = (self.window_size - H % self.window_size) % self.window_size
x = F.pad(x, (0, 0, pad_l, pad_r, pad_t, pad_b))
_, Hp, Wp, _ = x.shape
# cyclic shift
if self.shift_size > 0:
# 对窗口进行移位。从上向下移,从左往右移,因此是负的
shifted_x = torch.roll(x, shifts=(-self.shift_size, -self.shift_size), dims=(1, 2))
else:
shifted_x = x
attn_mask = None
# 划分窗口 windows
x_windows = window_partition(shifted_x, self.window_size) # [nW*B, Mh, Mw, C]
# # [nW*B, Mh*Mw]输入进行# [nW*B, Mh*Mw, C]attention
x_windows = x_windows.view(-1, self.window_size * self.window_size, C)
# W-MSA/SW-MSA
attn_windows = self.attn(x_windows, mask=attn_mask) # [nW*B, Mh*Mw, C]
# 窗口还原
attn_windows = attn_windows.view(-1, self.window_size, self.window_size, C) # [nW*B, Mh, Mw, C]
shifted_x = window_reverse(attn_windows, self.window_size, Hp, Wp) # [B, H', W', C]
# shift还原,如果没有shifted就不用还原
if self.shift_size > 0:
x = torch.roll(shifted_x, shifts=(self.shift_size, self.shift_size), dims=(1, 2))
else:
x = shifted_x
if pad_r > 0 or pad_b > 0:
# 把前面pad的数据移除掉
x = x[:, :H, :W, :].contiguous()
x = x.view(B, H * W, C)
# FFN MLP[不改变维度的]
# 改编为度是merge
x = shortcut + self.drop_path(x)
x = x + self.drop_path(self.mlp(self.norm2(x)))
return x
接下来是MERGE
class PatchMerging(nn.Module):
r""" Patch Merging Layer.
Args:
dim (int): Number of input channels.
norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm
"""
def __init__(self, dim, norm_layer=nn.LayerNorm):
super().__init__()
self.dim = dim
self.norm = norm_layer(4 * dim)
self.reduction = nn.Linear(4 * dim, 2 * dim, bias=False) # 将通道数由4倍变为2倍
def forward(self, x, H, W):
"""
x: B, H*W(L), C,并不知道H和W,所以需要单独传参
"""
# 1222222222
B, L, C = x.shape
assert L == H * W, "input feature has wrong size"
x = x.view(B, H, W, C)
# padding
# 因为是下采样两倍,如果输入feature map的H,W不是2的整数倍,需要进行padding
pad_input = (H % 2 == 1) or (W % 2 == 1)
if pad_input:
# 此时(B,H,W,C)依然是从后向前
# (C_front, C_back, W_left, W_right, H_top, H_bottom)
# 注意这里的Tensor通道是[B, H, W, C],所以会和官方文档有些不同
x = F.pad(x, (0, 0, 0, W % 2, 0, H % 2))
x0 = x[:, 0::2, 0::2, :] # [B, H/2, W/2, C]
x1 = x[:, 1::2, 0::2, :] # [B, H/2, W/2, C]
x2 = x[:, 0::2, 1::2, :] # [B, H/2, W/2, C]
x3 = x[:, 1::2, 1::2, :] # [B, H/2, W/2, C]
x = torch.cat([x0, x1, x2, x3], -1) # [B, H/2, W/2, 4*C],这里的-1就是在C的维度上拼接
x = x.view(B, -1, 4 * C) # [B, H/2*W/2, 4*C]
x = self.norm(x)
x = self.reduction(x) # [B, H/2*W/2, 2*C]
return x
patch merging
第一个先进行 H/4*W/4*48 48维度得 第一个48——C——2C——4C——8C 每一个模块经过了2268
注意力机制讲解
先进行编码排列。H/4*W/4*48 先补全7*7得倍数窗口(补0)对于每一个图片
W-MAS不考虑窗口移动
先是窗口设置(H*W/49,7*7,*C)
经过MLP(H*W/49,7*7,3C)
(3,H*W/49,3,7*7,C/3) 第一个三指的是qkv三个矩阵 第二个三头数 进行自适应计算
计算完后就是原来图像形况
12.1 Swin-Transformer网络结构详解_哔哩哔哩_bilibili
SW-MSA层我们需要考虑窗口移动与自注意编码
16 RNN与LSTM
如何从RNN起步,一步一步通俗理解LSTM_rnn lstm-CSDN博客
1 RNN
为了解决文字语言的:序列形的数据就不太好用原始的神经网络处理了,引入了隐状态h(hidden state)的概念,隐状态h可以对序列形的数据提取特征,接着再转换为输出。
2 LSTM
本质:
σ表示的Sigmoid 激活函数与 tanh 函数类似,不同之处在于 sigmoid 是把值压缩到0~1 之间而不是 -1~1 之间。这样的设置有助于更新或忘记信息:
因为任何数乘以 0 都得 0,这部分信息就会剔除掉;
同样的,任何数乘以 1 都得到它本身,这部分信息就会完美地保存下来。
LSTM核心
忘记门
输入门
细胞状态
输出门
17 姿态估计
1 openpose
openpose原理以及各种细节的介绍_openpose介绍_QTreeY123的博客-CSDN博客
热图原理:在实际打标签的时候就需要把标签做成热度图,而且在实际肩膀的位置是1,如果你打的点远离肩膀,那就是0.9,0.8,0.7,每一个点都要进行高斯分布形成一个热度图
以前的姿态估计不可以,以前的事先检测后进行姿态估计,为了在追求效率我们直接检测关键点,然后进行拼接
标签制作
我认为指的是一个标签变成了一个区域的意思,这个区域内的点进行计算 :限定区域得到的是不同地方的区域计算,别的一个给定的是向量标签问题
计算比较
得到的是每个点的任意向量进行投影计算,得到计算值,求积分。
如何一个个匹配?
a就与b匹配其他不考虑一个个解决再说 匈牙利算法
整体框架:
2 匈牙利算法
理解匈牙利算法_hungarian linear sum minimization-CSDN博客
sklearn 来计算
18 图像融合
注意:融合是没有标签的,和gan一样,自编码器也是一样的
定义:图像融合是指将多幅图像的信息融合在一起,生成一幅新的图像,使得新图像能够包含原始图像的所有关键信息和特征
原理:特征融合,该方法将多幅图像的特征进行提取和匹配,然后根据匹配结果进行融合。常用的特征包括边缘、纹理、颜色等
分类:
红外与可见光图像融合:将红外图像和可见光图像进行融合,可以提高目标检测和识别的性能
摇杆图像:将多源的遥感图像进行融合,可以提高地物的识别和分析能力
方法:见微信
评价指标
一文读懂信息熵、交叉熵和相对熵(KL散度) - 知乎 (zhihu.com)
图像融合质量评价方法SSIM、PSNR、EN、MSE与NRMSE(一)-CSDN博客
信息熵 标准差 结构相似度 均方误差 MSE(越小越好,其他都是越大越好)均方根误差
损失函数
loss=loss_int+loss_grad+loss_SSIM
其他方式:gan网络指的是两个鉴别器 自编码器指的是两个阶段的网络
19 目标检测
1 yolo1检测
YOLO系列详解:YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5、YOLOv6、YOLOv7_AI追随者的博客-CSDN博客YOLO系列详解:YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5、YOLOv6、YOLOv7_AI追随者的博客-CSDN博客YOLO系列详解:YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5、YOLOv6、YOLOv7_AI追随者的博客-CSDN博客
置信度:
高置信度会结果很全面但是不精确,低的相反。
AP:均值计算
流程:
本质的流程
图片输入进去,得到7*7*30 7*7 指的是分的图像的部分总共7*7个 30个维度如下图所示:
- 每个bounding box要预测(x, y, w, h)和confidence共5个值,每个网格还要预测一个类别信息,记为C类。则SxS个网格,每个网格要预测B个bounding box还要预测C个categories。输出就是S x S x (5*B+C)的一个tensor。
- class信息是针对每个网格的,confidence信息是针对每个bounding box的。
损失函数
损失函数有两个地方:
1 不同的损失函数权重不一样的,位置误差更大一点
2 如果没有物体的也需要损失函数
非极大值抑制:选取最大的最好的那个置信度
问题
小问题一般化
2 yolo2检测
Draknet19
深度学习目标检测_YOLOV2超详细解读_yolov2结构图-CSDN博客
此外预测方式也发生了改变
第一个:为什么输入是416?为什么是400+,不是224呢,因为这样可以让图片分辨率更好
因为2^5可以把416整除这样的话。此外因为:
第二个 网络图很像VGG16所以,而且没有线性层,最后一层conv很特殊
第三个先验框的提取 聚类的方法,采用的iou面积来计算的
通过计算选取不同的先验框来计算原先是9个
有一个问题?为什么可以取
第四个怎么预测的?
V2中没有使用偏移量,而是选择相对gride cell 的偏移量。
把每一个格子看成1来计算的,且看的是相对于左上角的
第五个问题?如何训练的
3 yolo3 检测
网络:
输出信息类别
所谓的多尺度就是来自这3条预测之路,y1,y2和y3的深度都是255,边长的规律是13:26:52。YOLOv3设定的是每个网格单元预测3个box,所以每个box需要有(x, y, w, h, confidence)五个基本参数,然后还要有80个类别的概率。所以3×(5 + 80) = 255,这个255就是这么来的。
softmax的改进
相当于每一个类别进行sigomid的运用
4 yolo4 检测
数据增强小技巧
YOLOv4中的tricks概念总结——Bag of freebies_Clichong的博客-CSDN博客
随机设置补丁,label Smoothing——改变标签
IOU计算
IOU_Loss:主要考虑检测框和目标框重叠面积。
GIOU_Loss:在IOU的基础上,解决边界框不重合时的问题。——引入差集
DIOU_Loss:在IOU和GIOU的基础上,考虑边界框中心点距离的信息。——引入中心距离
CIOU_Loss:在DIOU的基础上,考虑边界框宽高比的尺度信息。——衡量长宽比一致性的参数
YOLOv4中采用了CIOU_Loss的回归方式,使得预测框回归的速度和精度更高一些。
DIOU-NMS
降低重叠的图像
归一化操作
【YOLO v4 相关理论】Normalization: BN、CBN、CmBN_yolov4中的batchnormalization网络-CSDN博客
BN每一个mini batch进行运算 CBN前几个mini batch进行运算 CmBN一个整个的batch进行计算
网络结构
对于backbone
CV 经典主干网络 (Backbone) 系列: CSPNet_cv里面backbone-CSDN博客
SPP
YOLO系列详解:YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5、YOLOv6、YOLOv7_AI追随者的博客-CSDN博客
SPP(Spatial Pyramid Pooling)解读_spp结构-CSDN博客
FAN
1 加一起变成拼接
好处:
引入了自底向上的路径,使得底层信息更容易传到顶部
并且还是一个捷径,红色的没准走个100层(Resnet),绿色的几层就到了
总结:
backbone改变了
conv的一部分用mish改变
下采样采用了SPP
消除敏感度
提出了空间注意力机制
5 yolo5 检测
1+2+1+2 1csp在neck存在 2 两个残差快 1 focus 2 自适应模块
YOLO系列梳理(三)YOLOv5_yolov5自适应锚框_CV技术指南(公众号)的博客-CSDN博客
不同之处:
1 相比于V4 CSP不仅在backbone存在,在neck里面也存在的
2 CSP结构-YOLOv4网络结构中,借鉴了CSPNet的设计思路,仅仅在主干网络中设计了CSP结构。而YOLOv5中设计了两种CSP结构,以YOLOv5s网络为例,CSP1_X结构应用于Backbone主干网络中,另一种CSP2_X结构则应用于Neck网络中
Focus 操作
自适应框选
自适应图片缩放
YOLOv5 提出一种方法能够自适应的添加最少的黑边到缩放之后的图片
focus
残差网络有两种
YOLOv5网络模型的结构原理讲解(全)_yolov5网络结构详解-CSDN博客
6 yolo6 检测
1+1+1
YOLO v6:一个硬件友好的目标检测算法_解耦检测头-CSDN博客
YOLO系列详解:YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5、YOLOv6、YOLOv7-CSDN博客
YOLOv6 主要在 Backbone、Neck、Head 以及训练策略等方面进行了诸多的改进:
统一设计了更高效的 Backbone 和 Neck :受到硬件感知神经网络设计思想的启发,基于 RepVGG style设计了可重参数化、更高效的骨干网络 EfficientRep Backbone 和 Rep-PAN Neck。
优化设计了更简洁有效的 Efficient Decoupled Head,在维持精度的同时,进一步降低了一般解耦头带来的额外延时开销。
Anchor-free 无锚范式,SimOTA标签分配策略以及 SIoU边界框回归损失来进一步提高检测精度。
backbone
具体图
结合图差不多的。主要有一个SimSPPF
空间金字塔池化改进 SPP / SPPF / SimSPPF / ASPP / RFB / SPPCSPC / SPPFCSPC_金字塔池化模块-CSDN博客
neck
FAN里面的csp变成rep
检测头部
基于yolox改进得到的
在 YOLOv6 中,我们采用了解耦检测头(Decoupled Head)结构,并对其进行了精简设计。原始 YOLOv5 的检测头是通过分类和回归分支融合共享的方式来实现的,而 YOLOX 的检测头则是将分类和回归分支进行解耦,同时新增了两个额外的 3x3 的卷积层,虽然提升了检测精度,但一定程度上增加了网络延时。
因此,我们对解耦头进行了精简设计,同时综合考虑到相关算子表征能力和硬件上计算开销这两者的平衡,采用 Hybrid Channels 策略重新设计了一个更高效的解耦头结构,在维持精度的同时降低了延时,缓解了解耦头中 3x3 卷积带来的额外延时开销。通过在 nano 尺寸模型上进行消融实验,对比相同通道数的解耦头结构,精度提升 0.2% AP 的同时,速度提升6.8%。
SIOU损失函数
目标检测--边框回归损失函数SIoU原理详解及代码实现_边框损失函数-CSDN博客
simOTA 细节学习
目标检测标签分配之 OTA 和 SimOTA 细节学习-CSDN博客
首先是3*1000 3个物体 1000个候选框
选取前十个进行当成正样本
正样本加一起得到一个值 文中里面的是 343
然后进行选取最大的当成正样本
速度快,但是效果低了
7 yolo7 检测
给一个结构图看吧 up不写了太累了
补充知识点:检测指标知识点
目标检测评价指标-CSDN博客【语义分割】评价指标:PA、CPA、MPA、IoU、MIoU详细总结和代码实现_语义分割mpa计算公式-CSDN博客目标检测评价指标-CSDN博客
8 yolov8
TAL标签策略:根据cls和reg的loss来计算
import torch
import torch.nn.functional as F
class TALAssigner:
def __init__(self, num_classes, alpha=0.25, gamma=2.0, iou_threshold=0.5):
self.num_classes = num_classes
self.alpha = alpha
self.gamma = gamma
self.iou_threshold = iou_threshold
def compute_cls_loss(self, preds, targets):
# preds: [N, num_classes]
# targets: [N, num_classes] (one-hot encoded)
p_t = preds * targets + (1 - preds) * (1 - targets)
alpha_t = self.alpha * targets + (1 - self.alpha) * (1 - targets)
focal_weight = alpha_t * (1 - p_t).pow(self.gamma)
cls_loss = F.binary_cross_entropy(preds, targets, reduction='none')
return focal_weight * cls_loss
def compute_reg_loss(self, preds, targets):
# preds: [N, 4]
# targets: [N, 4]
diff = torch.abs(preds - targets)
reg_loss = torch.where(diff < 1, 0.5 * diff.pow(2), diff - 0.5)
return reg_loss.sum(-1)
def forward(self, cls_preds, reg_preds, cls_targets, reg_targets):
# cls_preds: [N, num_classes]
# reg_preds: [N, 4]
# cls_targets: [N, num_classes]
# reg_targets: [N, 4]
cls_loss = self.compute_cls_loss(cls_preds, cls_targets)
reg_loss = self.compute_reg_loss(reg_preds, reg_targets)
total_loss = cls_loss + reg_loss
assigned_indices = total_loss < self.iou_threshold
return assigned_indices, total_loss
# Example usage
num_classes = 80
tal_assigner = TALAssigner(num_classes)
cls_preds = torch.rand(100, num_classes) # 模拟分类预测
reg_preds = torch.rand(100, 4) # 模拟回归预测
cls_targets = F.one_hot(torch.randint(0, num_classes, (100,)), num_classes) # 模拟分类标签
reg_targets = torch.rand(100, 4) # 模拟回归标签
assigned_indices, total_loss = tal_assigner(cls_preds, reg_preds, cls_targets, reg_targets)
simoat指的是选取iou最好的几个来计算
import torch
class SimOTAAssigner:
def __init__(self, topk=5, iou_threshold=0.5):
self.topk = topk
self.iou_threshold = iou_threshold
def compute_iou(self, boxes1, boxes2):
# Compute IoU between two sets of boxes
inter = self.compute_intersection(boxes1, boxes2)
area1 = (boxes1[:, 2] - boxes1[:, 0]) * (boxes1[:, 3] - boxes1[:, 1])
area2 = (boxes2[:, 2] - boxes2[:, 0]) * (boxes2[:, 3] - boxes2[:, 1])
union = area1[:, None] + area2[None, :] - inter
iou = inter / union
return iou
def compute_intersection(self, boxes1, boxes2):
# Compute the intersection area of two sets of boxes
lt = torch.max(boxes1[:, None, :2], boxes2[:, :2])
rb = torch.min(boxes1[:, None, 2:], boxes2[:, 2:])
wh = (rb - lt).clamp(min=0)
return wh[:, :, 0] * wh[:, :, 1]
def forward(self, reg_preds, reg_targets):
# reg_preds: [N, 4]
# reg_targets: [M, 4]
iou_matrix = self.compute_iou(reg_preds, reg_targets)
# Find top-k matches
topk_values, topk_indices = torch.topk(iou_matrix, self.topk, dim=0)
# Filter out matches below IoU threshold
assigned_indices = topk_values > self.iou_threshold
return assigned_indices, topk_indices
# Example usage
simota_assigner = SimOTAAssigner()
reg_preds = torch.rand(100, 4) # 模拟回归预测
reg_targets = torch.rand(10, 4) # 模拟回归标签
assigned_indices, topk_indices = simota_assigner(reg_preds, reg_targets)
9 RGB-T检测
20 分割任务
1 Unet解读
分割focal loss
深度学习分割任务——Unet++分割网络代码详细解读(文末附带作者所用code)-CSDN博客
【语义分割】评价指标:PA、CPA、MPA、IoU、MIoU详细总结和代码实现_语义分割mpa计算公式-CSDN博客
class Unet(nn.Module):
def __init__(self):
super().__init__()
self.encoder_conv = nn.Sequential(DoubleConv2d(1,64)
,DoubleConv2d(64,128)
,DoubleConv2d(128,256)
,DoubleConv2d(256,512)
)
self.encoder_down = nn.MaxPool2d(2)
self.decoder_up = nn.Sequential(nn.ConvTranspose2d(1024,512,4,2,1)
,nn.ConvTranspose2d(512,256,4,2,1)
,nn.ConvTranspose2d(256,128,4,2,1)
,nn.ConvTranspose2d(128,64,4,2,1)
)
self.decoder_conv = nn.Sequential(DoubleConv2d(1024,512)
,DoubleConv2d(512,256)
,DoubleConv2d(256,128)
,DoubleConv2d(128,64)
)
self.bottleneck = DoubleConv2d(512,1024)
self.output = nn.Conv2d(64,2,3,1,1)
def forward(self,x):
#encoder:保存每一个DoubleConv的结果为跳跃链接做准备,同时输出codes
skip_connection = []
for idx in range(4):
x = self.encoder_conv[idx](x)
skip_connection.append(x)
x = self.encoder_down(x)
x = self.bottleneck(x)
#调换顺序
skip_connection = skip_connection[::-1]
#decoder:codes每经过一个转置卷积,就需要与跳跃链接中的值合并
#合并后的值进入DoubleConv
for idx in range(4):
x = self.decoder_up[idx](x)
#转换尺寸
skip_connection[idx] = transforms.functional.resize(skip_connection[idx],size=x.shape[-2:])
x = torch.cat((skip_connection[idx],x),dim=1)
x = self.decoder_conv[idx](x)
x = self.output(x)
return x
这个里面指的是cat 通道数进行相加得到的
2 U-net++
从denseNet弄来的
【语义分割】U-Net++_u-net++缺陷-CSDN博客
为什么这么做:
作者认为:当 Encoder 和 Decoder 网络的特征映射在语义上相似时,优化器能更好的处理学习任务。因此,设计了一系列nested (嵌套的),dense (密集的) skip pathways (跳跃路径),将高分辨率特征图从 Encoder 网络逐渐地和 Decoder 网络中相应语义的特征图优先进行融合,通过叠加的方式整合,以此来获取不同层次的特征。此外,该网络还加入了更浅的U-Net,使得融合的特征图尺度差异更小,更能高效地捕获前景对象的深层 ( fine-grained ) 细节
图像增强工具 albumentations学习总结 - hou永胜 - 博客园 (cnblogs.com)数据增强
深度学习100问-15:什么是深监督(Deep Supervision)?-CSDN博客
相当于一个辅助分类器
3 U2-net
和Unet感觉差不多,大的讨一个小的
RSU-7结构
RSU-4F结构
其中En_1
和De_1
采用的是RSU-7
,En_2
和De_2
采用的是RSU-6
,En_3
和De_3
采用的是RSU-5
,En_4
和De_4
采用的是RSU-4
,最后还剩下En_5
、En_6
和De_5
三个模块。这三个模块采用的是RSU-4F
在RSU-4F中并没有进行下采样或上采样,而是将采样层全部替换成了膨胀卷积。作者在论文3.2章节中的解释是到En_5时,特征图的分辨率已经很低了,如果接着下采样会丢失很多上下文信息,所以在RSU-4F中就不再进行下采样了。下图是我绘制的RSU-4F,其中带参数d的卷积层全部是膨胀卷积,d为膨胀系数。
3 deeplab
Deeplabv3+网络结构详解与模型的搭建_如何更改deeplabv3+的主干网络-CSDN博客
deeplab V3
pytorch 官网给的
v3把atrous换成普通的卷积而已
backbone 指的是resnet50
v3+
相当于把conv换成了深度可分离卷积
源码解析
deeplab v3+ 源码详解_deeplabv3代码-CSDN博客
def get_argparser():
parser = argparse.ArgumentParser()
# Datset Options
# 数据参数
parser.add_argument("--data_root", type=str, default='./datasets/data',
help="path to Dataset")
#数据集类型
parser.add_argument("--dataset", type=str, default='voc',
choices=['voc', 'cityscapes'], help='Name of dataset')
parser.add_argument("--num_classes", type=int, default=None,
help="num classes (default: None)")
# 网络模型
parser.add_argument("--model", type=str, default='deeplabv3plus_mobilenet',
choices=['deeplabv3_resnet50', 'deeplabv3plus_resnet50',
'deeplabv3_resnet101', 'deeplabv3plus_resnet101',
'deeplabv3_mobilenet', 'deeplabv3plus_mobilenet'], help='model name')
# 裁剪
parser.add_argument("--separable_conv", action='store_true', default=False,
help="apply separable conv to decoder and aspp")
parser.add_argument("--output_stride", type=int, default=16, choices=[8, 16])
# 训练过程
parser.add_argument("--test_only", action='store_true', default=False)
#
parser.add_argument("--save_val_results", action='store_true', default=False,
help="save segmentation results to \"./results\"")
# 总的次数
parser.add_argument("--total_itrs", type=int, default=30e3,
help="epoch number (default: 30k)")
# 学习率
parser.add_argument("--lr", type=float, default=0.01,
help="learning rate (default: 0.01)")
# 学习率衰减
parser.add_argument("--lr_policy", type=str, default='poly', choices=['poly', 'step'],
help="learning rate scheduler policy")
#迭代的次数
parser.add_argument("--step_size", type=int, default=10000)
#验证集要不要裁剪
parser.add_argument("--crop_val", action='store_true', default=False,
help='crop validation (default: False)')
# 样本量
parser.add_argument("--batch_size", type=int, default=16,
help='batch size (default: 16)')
parser.add_argument("--val_batch_size", type=int, default=4,
help='batch size for validation (default: 4)')
#输入输入大小
parser.add_argument("--crop_size", type=int, default=513)
parser.add_argument("--ckpt", default=None, type=str,
help="restore from checkpoint")
parser.add_argument("--continue_training", action='store_true', default=False)
parser.add_argument("--loss_type", type=str, default='cross_entropy',
choices=['cross_entropy', 'focal_loss'], help="loss type (default: False)")
parser.add_argument("--gpu_id", type=str, default='0',
help="GPU ID")
parser.add_argument("--weight_decay", type=float, default=1e-4,
help='weight decay (default: 1e-4)')
parser.add_argument("--random_seed", type=int, default=1,
help="random seed (default: 1)")
# 打印几次每隔几次
parser.add_argument("--print_interval", type=int, default=10,
help="print interval of loss (default: 10)")
# 验证机打印
parser.add_argument("--val_interval", type=int, default=100,
help="epoch interval for eval (default: 100)")
#是否加载预训练模型
parser.add_argument("--download", action='store_true', default=False,
help="download datasets")
# 选择版本
parser.add_argument("--year", type=str, default='2012',
choices=['2012_aug', '2012', '2011', '2009', '2008', '2007'], help='year of VOC')
# 要不要进行展示
parser.add_argument("--enable_vis", action='store_true', default=False,
help="use visdom for visualization")
parser.add_argument("--vis_port", type=str, default='13570',
help='port for visdom')
parser.add_argument("--vis_env", type=str, default='main',
help='env for visdom')
parser.add_argument("--vis_num_samples", type=int, default=8,
help='number of samples for visualization (default: 8)')
return parser
模型:
deeplab v3+ 源码详解_deeplabv3代码-CSDN博客DeepLabV3使用及源码讲解_deeplabv3代码-CSDN博客
21 时序任务
就是一种思想
22 注意力机制
1 CBMA
通道有一个线性层计算
class ChannelAttention(nn.Module):
"""
CBAM混合注意力机制的通道注意力
"""
def __init__(self, in_channels, ratio=16):
super(ChannelAttention, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.max_pool = nn.AdaptiveMaxPool2d(1)
self.fc = nn.Sequential(
# 全连接层
# nn.Linear(in_planes, in_planes // ratio, bias=False),
# nn.ReLU(),
# nn.Linear(in_planes // ratio, in_planes, bias=False)
# 利用1x1卷积代替全连接,避免输入必须尺度固定的问题,并减小计算量
nn.Conv2d(in_channels, in_channels // ratio, 1, bias=False),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels // ratio, in_channels, 1, bias=False)
)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avg_out = self.fc(self.avg_pool(x))
max_out = self.fc(self.max_pool(x))
out = avg_out + max_out
out = self.sigmoid(out)
return out * x
class SpatialAttention(nn.Module):
"""
CBAM混合注意力机制的空间注意力
"""
def __init__(self, kernel_size=7):
super(SpatialAttention, self).__init__()
assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
padding = 3 if kernel_size == 7 else 1
self.conv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avg_out = torch.mean(x, dim=1, keepdim=True)
max_out, _ = torch.max(x, dim=1, keepdim=True)
out = torch.cat([avg_out, max_out], dim=1)
out = self.sigmoid(self.conv1(out))
return out * x
2 SE 注意力机制
附加一些小问题
面试经验1
list如何删选不重复元素?
numpy如何解决
如何把数据输入到cpu上训练
torch.detach什么意思?有什么作用?
如何冻结torch的层
BN层训练和测试时候有什么区别?
torch.train与torch.eval之间的关系
目标检测里面的AP怎么计算的?
tansformer里面的QKV维度怎么变化的?
# 10 是原来特征 20是后来的特征 2 是头数 头数必须和feature的channel一样才可以。 # 流程主要是先进行 线性层+拆开特征数+进行操作 # (32, 20, 10)——(MLP)(32,20,20)——(32,20,2,10)——(attn)(32,2,20,20)——(32,20,2,10)——(32,20,20)
import torch
import numpy as np
import torch.nn as nn
import math
import torch.nn.functional as F
class selfAttention(nn.Module) :
def __init__(self, num_attention_heads, input_size, hidden_size):
super(selfAttention, self).__init__()
if hidden_size % num_attention_heads != 0 :
raise ValueError(
"the hidden size %d is not a multiple of the number of attention heads"
"%d" % (hidden_size, num_attention_heads)
)
self.num_attention_heads = num_attention_heads
self.attention_head_size = int(hidden_size / num_attention_heads)
self.all_head_size = hidden_size
self.key_layer = nn.Linear(input_size, hidden_size)
self.query_layer = nn.Linear(input_size, hidden_size)
self.value_layer = nn.Linear(input_size, hidden_size)
def trans_to_multiple_heads(self, x):
new_size = x.size()[ : -1] + (self.num_attention_heads, self.attention_head_size)
x = x.view(new_size)
return x.permute(0, 2, 1, 3)
def forward(self, x):
key = self.key_layer(x)
query = self.query_layer(x)
value = self.value_layer(x)
key_heads = self.trans_to_multiple_heads(key)
query_heads = self.trans_to_multiple_heads(query)
value_heads = self.trans_to_multiple_heads(value)
attention_scores = torch.matmul(query_heads, key_heads.permute(0, 1, 3, 2))
attention_scores = attention_scores / math.sqrt(self.attention_head_size)
attention_probs = F.softmax(attention_scores, dim = -1)
context = torch.matmul(attention_probs, value_heads)
context = context.permute(0, 2, 1, 3).contiguous()
new_size = context.size()[ : -2] + (self.all_head_size , )
context = context.view(*new_size)
return context
# 32是批次 20是词向量 10是特征
features = torch.rand((32, 20, 10))
# 10 是原来特征 20是后来的特征 2 是头数 头数必须和feature的channel一样才可以。
# 流程主要是先进行 线性层+拆开特征数+进行操作
attention = selfAttention(2, 10, 20)
result = attention.forward(features)
print(result.shape)
VIT里面的
# 1*3*480*480——1*768*30*30——1*768*900——1*900*3*12*64(3个qkv 12个头 64特征)qkv指的是900*12*64——(attn(1*12*900*900)里面就是注意力,reshape进行操作)接下来就是(1*900*768)
# MLP里面就是1*768*900 变成1*768*3072 变成1*768*900
import math
from collections import OrderedDict
from functools import partial
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
# --------------------------------------#
# Gelu激活函数的实现
# 利用近似的数学公式
# --------------------------------------#
class GELU(nn.Module):
def __init__(self):
super(GELU, self).__init__()
def forward(self, x):
return 0.5 * x * (1 + torch.tanh(np.sqrt(2 / np.pi) * (x + 0.044715 * torch.pow(x, 3))))
def drop_path(x, drop_prob: float = 0., training: bool = False):
if drop_prob == 0. or not training:
return x
keep_prob = 1 - drop_prob
shape = (x.shape[0],) + (1,) * (x.ndim - 1)
random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device)
random_tensor.floor_()
output = x.div(keep_prob) * random_tensor
return output
class DropPath(nn.Module):
def __init__(self, drop_prob=None):
super(DropPath, self).__init__()
self.drop_prob = drop_prob
def forward(self, x):
return drop_path(x, self.drop_prob, self.training)
class PatchEmbed(nn.Module):
def __init__(self, input_shape=[480, 480], patch_size=16, in_chans=3, num_features=768, norm_layer=None,
flatten=True):
super().__init__()
self.num_patches = (input_shape[0] // patch_size) * (input_shape[1] // patch_size)
self.flatten = flatten
self.proj = nn.Conv2d(in_chans, num_features, kernel_size=patch_size, stride=patch_size)
self.norm = norm_layer(num_features) if norm_layer else nn.Identity()
def forward(self, x):
# 1*3*480*480
x = self.proj(x)
# 1*768*30*30
if self.flatten:
x = x.flatten(2).transpose(1, 2) # BCHW -> BNC
x = self.norm(x)
return x
# --------------------------------------------------------------------------------------------------------------------#
# Attention机制
# 将输入的特征qkv特征进行划分,首先生成query, key, value。query是查询向量、key是键向量、v是值向量。
# 然后利用 查询向量query 点乘 转置后的键向量key,这一步可以通俗的理解为,利用查询向量去查询序列的特征,获得序列每个部分的重要程度score。
# 然后利用 score 点乘 value,这一步可以通俗的理解为,将序列每个部分的重要程度重新施加到序列的值上去。
# --------------------------------------------------------------------------------------------------------------------#
class Attention(nn.Module):
def __init__(self, dim, num_heads=12, qkv_bias=False, attn_drop=0., proj_drop=0.):
super().__init__()
self.num_heads = num_heads
self.scale = (dim // num_heads) ** -0.5
self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
self.attn_drop = nn.Dropout(attn_drop)
self.proj = nn.Linear(dim, dim)
self.proj_drop = nn.Dropout(proj_drop)
def forward(self, x):
B, N, C = x.shape
qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
q, k, v = qkv[0], qkv[1], qkv[2]
attn = (q @ k.transpose(-2, -1)) * self.scale
attn = attn.softmax(dim=-1)
attn = self.attn_drop(attn)
x = (attn @ v).transpose(1, 2).reshape(B, N, C)
x = self.proj(x)
x = self.proj_drop(x)
return x
# 1*3*480*480——1*768*30*30——1*768*900——1*900*3*12*64(3个qkv 12个头 64特征)qkv指的是900*12*64——(attn(1*12*900*900)里面就是注意力,reshape进行操作)接下来就是(1*900*768)
# MLP里面就是1*768*900 变成1*768*3072 变成1*768*900
class Mlp(nn.Module):
""" MLP as used in Vision Transformer, MLP-Mixer and related networks
"""
def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=GELU, drop=0.):
super().__init__()
out_features = out_features or in_features
hidden_features = hidden_features or in_features
drop_probs = (drop, drop)
self.fc1 = nn.Linear(in_features, hidden_features)
self.act = act_layer()
self.drop1 = nn.Dropout(drop_probs[0])
self.fc2 = nn.Linear(hidden_features, out_features)
self.drop2 = nn.Dropout(drop_probs[1])
def forward(self, x):
x = self.fc1(x)
x = self.act(x)
x = self.drop1(x)
x = self.fc2(x)
x = self.drop2(x)
return x
class Block(nn.Module):
def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, drop=0., attn_drop=0.,
drop_path=0., act_layer=GELU, norm_layer=nn.LayerNorm):
super().__init__()
self.norm1 = norm_layer(dim)
self.attn = Attention(dim, num_heads=num_heads, qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=drop)
self.norm2 = norm_layer(dim)
self.mlp = Mlp(in_features=dim, hidden_features=int(dim * mlp_ratio), act_layer=act_layer, drop=drop)
self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
def forward(self, x):
x = x + self.drop_path(self.attn(self.norm1(x)))
x = x + self.drop_path(self.mlp(self.norm2(x)))
return x
class Conv2dReLU(nn.Sequential):
def __init__(
self,
in_channels,
out_channels,
kernel_size,
padding=0,
stride=1,
use_batchnorm=True,
):
conv = nn.Conv2d(
in_channels,
out_channels,
kernel_size,
stride=stride,
padding=padding,
bias=not (use_batchnorm),
)
relu = nn.ReLU(inplace=True)
bn = nn.BatchNorm2d(out_channels)
super(Conv2dReLU, self).__init__(conv, bn, relu)
class VisionTransformer(nn.Module):
def __init__(
# patchsize指的是16*16 16个
self, input_shape=[480, 480], patch_size=16, in_chans=3, num_classes=2, num_features=768,
depth=12, num_heads=12, mlp_ratio=4., qkv_bias=True, drop_rate=0.1, attn_drop_rate=0.1, drop_path_rate=0.1,
norm_layer=partial(nn.LayerNorm, eps=1e-6), act_layer=GELU
):
super().__init__()
# -----------------------------------------------#
# 480, 480, 3 -> 196, 768
# -----------------------------------------------#
self.patch_embed = PatchEmbed(input_shape=input_shape, patch_size=patch_size, in_chans=in_chans,
num_features=num_features)
# 一个图像的尺寸是多少 900 30*30
num_patches = (480 // patch_size) * (480 // patch_size)
# 一个图像的特征是768
self.num_features = num_features
self.new_feature_shape = [int(input_shape[0] // patch_size), int(input_shape[1] // patch_size)]
self.old_feature_shape = [int(480 // patch_size), int(480 // patch_size)]
# --------------------------------------------------------------------------------------------------------------------#
# classtoken部分是transformer的分类特征。用于堆叠到序列化后的图片特征中,作为一个单位的序列特征进行特征提取。
#
# 在利用步长为16x16的卷积将输入图片划分成14x14的部分后,将14x14部分的特征平铺,一幅图片会存在序列长度为196的特征。
# 此时生成一个classtoken,将classtoken堆叠到序列长度为196的特征上,获得一个序列长度为197的特征。
# 在特征提取的过程中,classtoken会与图片特征进行特征的交互。最终分类时,我们取出classtoken的特征,利用全连接分类。
# --------------------------------------------------------------------------------------------------------------------#
# 196, 768 -> 197, 768
# cls_token=1*1*768
self.cls_token = nn.Parameter(torch.zeros(1, 1, num_features))
# --------------------------------------------------------------------------------------------------------------------#
# 为网络提取到的特征添加上位置信息。
# 以输入图片为480, 480, 3为例,我们获得的序列化后的图片特征为196, 768。加上classtoken后就是197, 768
# 此时生成的pos_Embedding的shape也为197, 768,代表每一个特征的位置信息。
# --------------------------------------------------------------------------------------------------------------------#
# 197, 768 -> 197, 768
self.pos_embed = nn.Parameter(torch.zeros(1, num_patches, num_features))
self.pos_drop = nn.Dropout(p=drop_rate)
# -----------------------------------------------#
# 197, 768 -> 197, 768 12次
# -----------------------------------------------#
dpr = [x.item() for x in torch.linspace(0, drop_path_rate, depth)]
self.blocks = nn.Sequential(
*[
Block(
dim=num_features,
num_heads=num_heads,
mlp_ratio=mlp_ratio,
qkv_bias=qkv_bias,
drop=drop_rate,
attn_drop=attn_drop_rate,
drop_path=dpr[i],
norm_layer=norm_layer,
act_layer=act_layer
) for i in range(depth)
]
)
self.norm = norm_layer(num_features)
self.head = nn.Linear(num_features, num_classes) if num_classes > 0 else nn.Identity()
n_patches = (480 // 16) * (480 // 16)
self.position_embeddings = nn.Parameter(torch.zeros(1, n_patches, 768))
self.conv_more = Conv2dReLU(
768,
2048,
kernel_size=3,
padding=1,
use_batchnorm=True,
)
def forward_features(self, x):
x = self.patch_embed(x)
# cls_token = self.cls_token.expand(x.shape[0], -1, -1)
# x = torch.cat((cls_token, x), dim=1)
#
# cls_token_pe = self.pos_embed[:, 0:1, :]
# img_token_pe = self.pos_embed[:, 1: , :]
# print(img_token_pe.shape)
#
# img_token_pe = img_token_pe.view(1, *self.old_feature_shape, -1).permute(0, 3, 1, 2)
# print(img_token_pe.shape)
# img_token_pe = F.interpolate(img_token_pe, size=self.new_feature_shape, mode='bicubic', align_corners=False)
# print(img_token_pe.shape)
# img_token_pe = img_token_pe.permute(0, 2, 3, 1).flatten(2)
# print(img_token_pe.shape)
# pos_embed = torch.cat([cls_token_pe, img_token_pe], dim=1)
# x = x.flatten(2)
# x = x.transpose(-1, -2)
x = x + self.position_embeddings
x = self.pos_drop(x)
x = self.blocks(x)
x = self.norm(x)
return x
def forward1(self, hidden_states):
B, n_patch, hidden = hidden_states.size() # reshape from (B, n_patch, hidden) to (B, h, w, hidden)
h, w = int(np.sqrt(n_patch)), int(np.sqrt(n_patch))
x = hidden_states.permute(0, 2, 1)
x = x.contiguous().view(B, hidden, h, w)
x = self.conv_more(x)
return x
def forward(self, x):
x = self.forward_features(x)
x = self.forward1(x)
# print(x.shape)
return x
def freeze_backbone(self):
backbone = [self.patch_embed, self.cls_token, self.pos_embed, self.pos_drop, self.blocks[:8]]
for module in backbone:
try:
for param in module.parameters():
param.requires_grad = False
except:
module.requires_grad = False
def Unfreeze_backbone(self):
backbone = [self.patch_embed, self.cls_token, self.pos_embed, self.pos_drop, self.blocks[:8]]
for module in backbone:
try:
for param in module.parameters():
param.requires_grad = True
except:
module.requires_grad = True
def vit(input_shape=[480, 480], pretrained=False, num_classes=2):
model = VisionTransformer(input_shape)
if pretrained:
model.load_state_dict(torch.load("model_data/vit-patch_16.pth"))
if num_classes != 1000:
model.head = nn.Linear(model.num_features, num_classes)
return model
import torch
# Create a random input tensor with the shape (batch_size, channels, height, width)
input_data = torch.randn((1, 3, 480, 480))
# Instantiate the Vision Transformer model
vit_model = vit(input_shape=[480, 480], num_classes=2)
# Forward pass through the model
output = vit_model(input_data)
# Print the shape of the output
print("Output shape:", output.shape)
面试经验2
神经网络里面,哪些层可以达到下采样作用?
1 池化层 2 步幅大于1的卷积层 3 深度可分离卷积层
激活函数有什么作用?
1 引入非线性 2 解决分类问题 3 引入稀疏表示 4 处理梯度消失问题
列出三种模型参数更新方式
列出四种常见的损失函数
另一篇笔记里面有:基础知识点
NMS代码
NMS的python实现_nms python-CSDN博客
import numpy as np
def non_max_sppse(pre_box, threshold=0.2):
for object_name, bbox in pre_box.items():
bbox_array = np.array(bbox, np.float32)
# 计算所有框的面积
x1, y1, x2, y2, source = bbox_array[:, 0], bbox_array[:, 1], bbox_array[:, 2], bbox_array[:, 3], bbox_array[:, 4]
areas = (x2 - x1 + 1) * (y2 - y1 + 1)
# 对置信度进行排序
order = source.argsort()[::-1]
keep = []
while order.size>0:
i = order[0]
keep.append(i)
xx1 = np.maximum(x1[i], x1[order[1:]])
yy1 = np.maximum(y1[i], y1[order[1:]])
xx2 = np.minimum(x2[i], x2[order[1:]])
yy2 = np.minimum(y2[i], y2[order[1:]])
inter = np.maximum(0, (xx2 - xx1 + 1)) * np.maximum(0, (yy2 - yy1 + 1))
iou = inter / (areas[i] + areas[order[1:]] - inter)
indexs = np.where(iou < threshold)[0] + 1
order = order[indexs]
bbox = bbox_array[keep]
pre_box[object_name] = bbox.tolist()
pre_box = pre_box
return pre_box
pre_box = {"dog": [[2, 8, 4, 15, 0.5], [3, 12, 5, 17, 0.1], [3, 9, 4, 15, 0.3], [3, 10, 5, 18, 0.6], [2, 15, 4, 23, 0.8]]}
a = non_max_sppse(pre_box, 0.2)
print(a)
卷积手撕卷积
import numpy as np
def conv2d(inputs, kernels, bias, stride, padding):
""""
inputs: c, h, w
kernels: out_ch , in_ch, kh, kw; in_ch == c
bias: out_ch
"""
c, h, w = inputs.shape
out_ch, in_ch, kh, kw = kernels.shape
h_out = 1 + (h + 2 * padding - kh) // stride
w_out = 1 + (h + 2 * padding - kh) // stride
outputs = np.zeros((out_ch, h_out, w_out))
inputs_pad = np.pad(inputs, ((0, 0), (padding, padding), (padding, padding)))
for i in range(h_out):
for j in range(w_out):
area = inputs_pad[:, i * stride:i * stride + kh, j * stride:j * stride + kw] # in_ch, k, k
outputs[:, i, j] = np.sum(area[None, :] * kernels, axis=(1, 2, 3)) + bias
return outputs
image = np.random.rand(3,8, 8).astype(np.float32)
kernels = np.random.rand(6,3,1, 1).astype(np.float32)
result = conv2d(inputs=image, kernels=kernels, bias=0, stride=2, padding=0)
# 打印结果
print("卷积结果:\n", result.shape)
注意力
import numpy as np
import torch
import torch.nn.functional as F
from torch import nn
import math
# 在计算自注意力的时候,首先计算每个元素的 Query 和所有其他元素的 Key 之间的相似度(通常用点积来计算),
# 然后对相似度进行, softmax(行方向上)操作得到权重,最后将这个权重应用到每个元素的 Value 上,再将所有元素的加权 Value 求和
# 就得到了当前元素的输出。
class SimpleAttention(nn.Module):
def __init__(self, dim, num_heads):
super().__init__()
self.num_heads = num_heads
self.dim = dim # dim是特征长度
self.head_dim = dim // num_heads
def forward(self, query, key, value, mask=None):
B, _, N = query.size() # N是序列长度
# 将输入的Q、K、V拆分为多头。 num_heads多头、 head_dim每个头的特征维度、 N是序列长度
query = query.view(B, self.num_heads, self.head_dim, N)
key = key.view(B, self.num_heads, self.head_dim, N)
value = value.view(B, self.num_heads, self.head_dim, N)
# 计算注意力分数。计算query和key的点积(dot product)。点积是相似性度量方法,
# 我们使用点积来衡量query和每个key之间的相似性,相似性越高,对应的value在最终的注意力输出中的权重就越大。
# sqrt这部分是在对点积的结果进行缩放(scaling),用于防止点积的结果过大,导致softmax函数的梯度过小,从而影响模型的训练。
attn_scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(self.head_dim)
# 如果提供了mask,将其应用到注意力分数上
if mask is not None:
attn_scores = attn_scores.masked_fill(mask == 0, float('-inf'))
# 计算注意力权重
attn_weights = F.softmax(attn_scores, dim=-1)
# 计算加权的V
output = torch.matmul(attn_weights, value)
# 合并多头
output = output.contiguous().view(B, -1, N)
return output
# 创建一个示例的多通道二维图片数据(4x4 像素,3个通道)
query = np.random.rand(3, 12, 12).astype(np.float32)
key = np.random.rand(3, 12, 12).astype(np.float32)
value = np.random.rand(3, 12, 12).astype(np.float32)
# 执行池化操作
SimpleAttention2 = SimpleAttention(dim=64, num_heads=8)
results = SimpleAttention2(query, key, value)
# 打印卷积结果
print(results.shape)
手撕池化
import numpy as np
def max_pooling(inputs, pool_size, stride):
"""
最大池化操作
inputs: 输入数据,形状为 (C, H, W)
pool_size: 池化核的大小
stride: 步长
"""
C, H, W = inputs.shape
# 初始化输出数据
H_out = (H - pool_size) // stride + 1
W_out = (W - pool_size) // stride + 1
outputs = np.zeros((C, H_out, W_out))
# 进行最大池化操作
for i in range(H_out):
for j in range(W_out):
inputs_slice = inputs[:, i*stride:i*stride+pool_size, j*stride:j*stride+pool_size]
outputs[:, i, j] = np.max(inputs_slice, axis=(1, 2)) # 最大池化
# outputs[:, i, j] = np.mean(inputs_slice, axis=(1, 2)) # 平均池化
return outputs
# 创建一个示例的多通道二维图片数据(4x4 像素,3个通道)
image = np.random.rand(3, 12, 12).astype(np.float32)
# 定义 池化核大小
pool_size = 2
# 执行池化操作
result = max_pooling(image, pool_size, stride=2)
# 打印卷积结果
print(result.shape)
IOU代码
import numpy as np
def IoU_cal(box1, box2):
x1 = max(box1[0], box2[0])
y1 = max(box1[1], box2[1])
x2 = min(box1[2], box2[2])
y2 = min(box1[3], box2[3])
inter = max(0, x2 - x1) * max(0, y2 - y1)
areas1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
areas2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
iou = inter / (areas1 + areas2 - inter)
return iou
pre_box1 = [2, 9, 4, 15, 0.5]
pre_box2 = [3, 7, 6, 10, 0.5]
a = IoU_cal(pre_box1, pre_box2)
print(a)
BN手撕
import numpy as np
def batch_norm(inputs, gamma, beta, eps):
"""
批量归一化操作。N, C, H, W样本数可以看做N*H*W,CNN中,BN通常在每个通道上独立进行
inputs: 输入数据,形状为 (N, C, H, W)
gamma: 缩放因子,形状为 (C,)
beta: 偏移因子,形状为 (C,)
eps: 防止除0的小数值
"""
N, C, H, W = inputs.shape
# 在N、H和W的维度上计算每个通道的均值和方差
mean = np.mean(inputs, axis=(0, 2, 3), keepdims=True) # (1,C,1,1)
var = np.var(inputs, axis=(0, 2, 3), keepdims=True)
# 计算归一化的输入。eps防止除0
inputs_norm = (inputs - mean) / np.sqrt(var + eps)
# 缩放和偏移
outputs = gamma * inputs_norm + beta
return outputs
# 举例
inputs = np.random.rand(64, 3, 128, 128) # 64 samples, 3 channels, 128x128 feature maps
gamma = 0.5
beta = 0.2
eps = 2e-12
outputs = batch_norm(inputs, gamma, beta, eps)
print('输出:', outputs.shape)
dataloder
#导入相关模块
from torch.utils.data import DataLoader,Dataset
from skimage import io,transform
import matplotlib.pyplot as plt
import os
import torch
from torchvision import transforms
import numpy as np
class AnimalData(Dataset): #继承Dataset
def __init__(self, root_dir, transform=None): #__init__是初始化该类的一些基础参数
self.root_dir = root_dir #文件目录
self.transform = transform #变换
self.images = os.listdir(self.root_dir)#目录里的所有文件
def __len__(self):#返回整个数据集的大小
return len(self.images)
def __getitem__(self,index):#根据索引index返回dataset[index]
image_index = self.images[index]#根据索引index获取该图片
img_path = os.path.join(self.root_dir, image_index)#获取索引为index的图片的路径名
img = io.imread(img_path)# 读取该图片
label = img_path.split('\\')[-1].split('.')[0]# 根据该图片的路径名获取该图片的label,具体根据路径名进行分割。我这里是"E:\\Python Project\\Pytorch\\dogs-vs-cats\\train\\cat.0.jpg",所以先用"\\"分割,选取最后一个为['cat.0.jpg'],然后使用"."分割,选取[cat]作为该图片的标签
sample = {'image':img,'label':label}#根据图片和标签创建字典
if self.transform:
sample = self.transform(sample)#对样本进行变换
return sample #返回该样本
面试经验3
RGB-T全称是什么?
T指的是thermal 热红外意思,大华相机的分辨率是RGB是640*512 T分辨率是1024*1024
对于图像分辨率怎么做?
Matlab 仿射变换 IR变成RGB
如何摆放RGB与T图像的相机——这个指的是一体的,旋转+平移就可以
相机标定怎么做?
融合网络怎么做?具体看总结
Sober算子,融合算子怎么计算
边缘检测之Sobel检测算子_sobel算子卷积核-CSDN博客
python+OpenCv笔记(十六):边缘检测原理(Sobel算子原理、Laplacian算子原理、Canny边缘检测原理)-CSDN博客sober是一阶算子,laplacian是二阶算子
根据他们梯度不同来计算的。
archor-base和archor-free
DenseNet结构好用的原因:
- 减轻了梯度消失
- 加强了feature的传递
- 更有效地利用了feature
- 一定程度上较少了参数数量
- 残差连接分支进一步优化信息流和梯
残差连接块好用的原因
1、缓解梯度消失问题
2、简化学习任务
3、提高网络收敛速度
4、防止过拟合
池化层
1、降低卷积层输出的特征维度,有效减少⽹络参数的同时还可以防⽌过拟合现象。池化中没有可学习参数;
耦合头 与 解耦头
全连接层作用
负责对卷积神经⽹络学习提取到的特征进⾏汇总,将多维的特征输⼊映射为⼆维的特征输出,⾼维表⽰样本批次,低维常常对应任务⽬标。
全连接层将特征提取得到的高维特征图映射成一维特征向量,该特征向量包含所有特征信息,可以转化为最终分类成各个类别的概率
激活函数作用
激活函数需要具备以下几点性质:
1. 连续并可导(允许少数点上不可导)的非线性函数;
2. 激活函数及其导函数要尽可能的简单,有利于提高网络计算效率。
3. 激活函数的导函数的值域要在一个合适的区间内,不能太大也不能太小,否则会影响训练的效率和稳定性。
transformer
- 特点:是一个seq2seq的自注意力模型,大量的纯使用自注意力——(缩放点积注意力)的模型;
- 网络结构:首先将输入句子编码成词向量,并加入位置编码,这里采用的是正余弦编码;以单头注意力为例,首先将词向量分别乘上wq、wk、wv三个系数矩阵,得到Q、K、V向量,然后计算点积缩放注意力,公式是:
再经过相加与layernorm,MLP等。
- 为什么用多头?想让模型同时在不同的位置上学习不同的子空间表示。想要让每个自注意力模块能够自己去学想要的特征信息,例如可能某个自注意力模块学习全局的注意力,另一个学习局部注意力,类似于卷积利用不同的通道学习不同的特征。
- 多头是怎么实现的?将每个单头注意力计算得到的向量进行concate拼接,然后用初始化好的w0矩阵投影到与输入一样的形状。
- 为什么需要位置编码?:NLP任务大多是以RNN、LSTM为代表的循环处理方式,模型本身是一种顺序结构,天生就包含位置信息。自注意力模型是一个加权求和过程,没有位置编码信息,因此Tr模型需要将位置编码加上;
- 为什么位置编码Patch Embeding是直接相加上去的?:直接相加与在词向量cat位置编码的效果一样,结果矩阵运算后都是进行相加操作;残差结构的存在保证位置信息不会丢失;位置参数不可学习;
- Layer Normalization:与Batch Norm在小排量上做归一化不同,Layer Normalization在每层上进行归一化,将每一层神经元的输入都转成均值方差都一样的,这样可以加快收敛;
Swin Transformer
- 是什么?:第一,在窗口内计算自注意力,减小了序列长度,计算复杂度随窗口大小线性增长——窗口大小固定的,则每个窗口自注意力计算的复杂度一样,窗口数量是随输入图片的size线性增长的,因此总的计算复杂度是随窗口个数(输入图像尺寸)线性增长;第二,滑动窗口保证了窗口间的交互,实现对全局的建模能力;第三,层级式的结构提供了各个尺度的信息,适合多尺度任务;
- window attention:(这里的patch与patch partition不一样,后者是对输入进行切分,前者是决定窗口注意力的计算范围)
- shifted window attention:经过普通的窗口移位后变成了9个窗口,而且形状不一,无法做到直接计算自注意力。为了保证计算量不变,采用循环移位并重新分成4个大窗口;然而移动后有些窗口的元素间没有关联(可能在最初输入时就没有联系),不应该计算注意力的,因此引入掩码,保证窗口间合理的计算注意力;最后计算完多头注意力之后,恢复成原来的位置;掩码是在不需要计算注意力的位置,加上一个绝对值很大的负数,这样在计算注意力时,完成softmax计算后对应位置的值几乎0。
- 相对位置编码:
- patch partition:将输入图片按照patch_size的大小进行切分,输入224*224*3,patch包含4*4个像素,则切分后为56*56*48,一共56*56个patch。与ViT中差不多,是用一次卷积完成的;
- patch merging:类似于池化操作,增大感受野,将相邻的小patch合并成一个大的patch。最后还进行了通道数减半,变为原来2倍,而不是4倍;在stage I后的都是使用了;
面试经验4
MAP的如何计算的
睿智的目标检测20——利用mAP计算目标检测精确度-CSDN博客
项目的数据增强手段
融合图像不存在数据增强,行人重识别存在
BN怎么做的:
- 作用(初衷):防⽌梯度弥散,可以使用更高的学习率,加快训练速度,为网络的权重提供了正则化,一定程度上防止了过拟合的问题,减少了droupout的使用,可以把训练数据彻底打乱。
- 公式: 与yi←γx~i+β,γ与β是两个可学习参数;
- 为什么需要用BN:可以把经过非线性函数映射后向取值区间极限饱和区靠拢的输入分布强制拉回到均值为0方差为1的比较标准的正态分布,使得非线性变换函数的输入值落入对输入比较敏感的区域,以此避免梯度消失问题,并使得训练更快。但单纯的使用归一化,会降低了模型的非线性表达能力,以sigmoid为例,BN可能将所有的输入变量限制在了sigmoid的线性区域,模型的表达能力下降,加入了超参数γ与β后,我们既可以对输入尺度上变换,也可以对输入进行平移变换。而且只要我们将俩个超参数分别设定为标准差和均值,就有可能还原最初的输入。
- BN在测试时与训练的区别(禾多)?对于BN,在训练时,是对每一批的训练数据进行归一化,也即用每一批数据的均值和方差;在测试时,比如进行一个样本的预测,就并没有batch的概念,因此,这个时候用的均值和方差是整个训练数据的均值和方差,这个可以通过移动平均法求得。
- 为什么训练的时候不计算整个数据集的均值与方差?每一批数据的均值和方差会有一定的差别,这种差别能够增加模型的鲁棒性,减少过拟合。BN一般要求将训练集完全打乱,并用一个较大的batch值,去缩小与整个数据集的差别。
L1与L2的正则化
L1与L2正则化——机器学习的知识:
L1是指权值向量w中各个元素的绝对值之和;
L2是指权值向量w中各个元素的平方和然后再求平方根;
以两维情况为例,在(w1, w2)平面上可以画出目标函数的等高线,而约束条件则成为平面上半径为C的一个范式球。等高线与范式球首次相交的地方就是最优解;
L1对应的是一个正方形,L2对应的是一个圆,显然,L1正则化时,大部分时候都会在角的地方相交,此时部分w为0,产生一个稀疏的模型;L2正则化时,大部分参数都是接近0的小数,优化快,训练平稳。
VIT的知识点
- 怎么分类的?在第一个位置加入了cls这个token用于分类,从196维度变成197维度,后面接一个MLP进行图片分类。
- 计算量:始终是在整个输入图像 (被切分成16*16的patch)上计算自注意力,patch尺寸固定的话,复杂度与图像的size呈平方倍的增长;
- 没有任何卷积过程,纯注意力,缺少归纳偏置;
- ViT没有下采样,中的token长度是不变的,一直是197,不利于多尺度预测任务,例如目标检测、语义分割;
偏差与方差?
偏差:是指预测值与真实值之间的差值.
方差:是衡量预测值之间的关系,和真实值无关.也就是他们的离散程度
误差 = 偏差 + 方差
噪声:噪声通常是出现在“数据采集”的过程中的,且具有随机性和不可控性;
SoftMax原理:
- 公式:
- 原理:归一化指数函数。是二分类函数sigmoid在多分类上的推广。它将多个神经元的输出,映射到(0,1)区间内,求和为1。适合多分类问题。
耦合头 与 解耦头:
Ycbcr<——>RGB: