第一章 数学基础
常用的向量与矩阵的范数总结[L0、L1、L2范数]_矩阵的2范数-CSDN博客
导数与偏导数区别:
第二章 机器学习
2.1 机器学习基本术语:
2.1.1 什么是监督学习
浅谈弱监督学习(Weakly Supervised Learning)-CSDN博客
2.2.3 弱监督学习
半监督学习就是弱监督学习得一种,就是不完全监督学习
2.1.2 分类算法的评估⽅法
语义分割指标_混淆矩阵计算指标_通过混淆矩阵计算iou-CSDN博客
SVM基本原理+核函数的意义 (绘制ROC曲线)
线性不可分加一个权重
非线性可分加一个和函数
准确率 指的是 00+11/总和
查准率:将多数类判错后所需付出成本“的衡量 多数类判断对的能力
查全率:找出少数类能力
假正率:多数类判断错误的能力
F综合指标
ROC曲线:捕捉少量类的时候,误伤多数类时候怎么变化
ROC曲线特性:当测试集中的正负样本的分布变换的时候,ROC曲线能够保持不
变。在实际的数据集中经常会出现样本类不平衡,即正负样本⽐例差距较⼤,⽽且测试数据中的正负样本也可能随着时间变化。
2.1.3 生成模型和判别模型比较
2.1.4 评估与误差分析
误差
2.1.5 类不平衡怎么办
1、扩⼤数据集
增加包含⼩类样本数据的数据,更多的数据能得到更多的分布信息。
2.1.6 模型评估和选择
k折交叉验证:为了得到更为稳健可靠的模型,对模型的泛化误差进⾏评估,得到模型泛化误差的近似值。当有多个模型可以选择时,我们通常选择“泛化误差”最⼩的模型。
2.2 逻辑回归
2.2.1基本知识点
sigmoid函数:
理解:
适用于:逻辑回归在金融领域,尤其是银行业中的统治地位依然不可动摇(相对的,逻辑回归在非线性数据的效果很多时候比瞎猜还不如,所以如果你已经知道数据之间的联系是非线性的,千万不要迷信逻辑回归)
损失函数——从伯努利分布得到的
L1与L2正则化的区别:
L1正则化和L2正则化虽然都可以控制过拟合,但它们的效果并不相同。当正则化强度逐渐增大(即C逐渐变小)参数的取值会逐渐变小,但L1正则化会将参数压缩为0,L2正则化只会让参数尽量小,不会取到0。
2.2.2 逻辑回归与朴素贝叶斯区别
2.2.3 线性回归和逻辑回归的区别
2.2.2 交叉熵损失函数与二次代价函数损失
2.2.3 常见的损失函数
2.2.4 梯度下降
梯度下降包括下面几种:
2.3 PCA算法
定义:
SVD与PCA的关系
2.3.1 总结:
用途:减少特征数量 保留大部分信息
如何寻找:寻找样本方差信息最大的,方差信息越大,携带信息量越多。
他们关系:但是通过SVD求解的 不需要求出XtX,也可以求出右奇异矩阵,因为是对维度降维,而不是行
理解:特征值表示的是这个特征到底有多重要,而特征向量表示这个特征是什么
看图
2.3.2 如何确定pca重要程度呢?
1 自己输入整数
2 最大似然估计自选超参数——自己选择
3 按信息量占比选超参数
2.3.3 降维的意义是什么:
1 减少变量个数 2 有利于可视化展示3 去除噪声
2.4 决策树
思想:分而治之
判别:1 信息增益——信息熵 越大越好 2 基尼指数——越小越好
如何剪枝:
2.5 支持向量机
2.5.1 线性的SVM
本身意义
总结一下:
1 先列出最优化的式子,然后判断总的式子满足KKT条件,所以可以强对偶接着由于求min的函数。
2 min的函数为了使得他大于1并且不含有约束条件 变成minmax, 强对偶的函数指的是原来的函数和变化的函数进行对比 使得max与min互换求导得到
3 对min里面的进行求导
2.5.2 非线性SVC
2.5.3 软间隔的SVM
2.5.4 与逻辑回归的不一样
2.6 聚类算法
2.6.1 为什么需要降维?
会发生过拟合的情况
2.6.2 分类情况
基于划分的聚类:聚类目标是使得类内的点足够近,类间的点足够远,常见的如k-means及其衍生算法基于密度的聚类:
当邻近区域的密度超过某个阈值,则继续聚类,如DBSCAN; OPTICS
层次聚类:这个下面会具体介绍到,包括合并的层次聚类,分裂的层次聚类,实际上可以看作是二叉树的生成和分裂过程。
2.7 集成学习
2.7.0 总结
stacking 得学习器很多类型 首先先训练多个不同的模型;然后把之前训练的各个模型的输出为输入来训练一个模型,以得到一个最终的输出。
bagging学习器都是一样得,并联——训练多个分类器取平均
数据集:采用有放回采样 权重:权重是均匀得
(随机森林)
boosting 学习器都是一样得,串联 基模型按次序一一进行训练(实现上可以做到并行),基模型的训练集按照某种策略每次都进行一定的转化
数据集:样本独立得 权重:根据错误率来进行提升
(AdaBoost, Xgboost,GBDT)
AdaBoost:对训练失败的训练例赋以较大的权重
GBDT:每一次的计算是为了减少上一次的残差
综上按照个体学习器之间的关系,集成学习一般分为Bagging、Boosting、Stacking三大类(我们可以把它简单地看成并行,串行和树型)。Bagging是把各个基模型的结果组织起来,取一个折中的结果;Boosting是根据旧模型中的错误来训练新模型,层层改进;Stacking是把基模型组织起来,注意不是组织结果,而是组织基模型本身,该方法看起来更灵活,也更复杂。
1)Bagging + 决策树 = 随机森林
2)AdaBoost + 决策树 = 自适应树—— 自适应的,通过修改样本权重,增大错误样本权重。
3)Gradient Boosting + 决策树 /GBDT=梯度树——每一次的计算是为了减少上一次的残差(负梯度)建立新模型
4) XGBoost ——自定义一套损失函数,借助泰勒展开,到极值点与对应极值即为所求采用多种分类器 是一种算法不是机器学习
2.7.1 随机森林
集成算法会考虑多个评估器的建模结果,汇总之后得到一个综合的结果,以此来获取比单个模型更好的回归或分类表现。
随机森林比较容易。
2.8 特征选择和预处理工程
2.8.1 特征选择:
方差过滤:对特征进行过滤
相关性过滤
卡方过滤: 统计特征与标签的卡方统计量
F检验:统计特征与标签的线性关系,表现的是线性关系
互信息法:统计特征与标签的非线性关系
嵌入法:根据特征的权值参数来计算的贡献
包装法:根据目标函数和涉及和特征的权值参数计算
2.8.2 预处理
2.8.2.1 无量纲化: 归一化+标准化
如何选择?
2.8.2.2 填充值
2.8.2.3 编码与哑变量(独热编码)
能够将分类特征转换为分类数值
哑变量如下图所示
2.8.2.4 二值化或者分段
第三章 深度学习基本知识
3.1、梯度、超参数、激活函数
梯度消失:梯度消失是指通过隐藏层从后向前看,梯度会变的越来越⼩,说明前⾯层的学习会
显著慢于后⾯层的学习 sigmoid
梯度爆炸:梯度可在⽹络更新的过程中不断累积,变成⾮常⼤的梯度,导致⽹络权重值的⼤幅更新,使得⽹络不稳定
有什么办法:预训练 换激活函数 bn 残差结构
超参数包括哪些,有什么方式:
学习率,激活函数,隐藏层数目
如何找: 网格搜索、随机搜索、贝叶斯优化、一个个试
为什么需要激活函数:
引入非线性函数、增加模型复杂度、得到非线性关系
激活函数的性质 看深度学习笔记
为什么sigmoid函数会出现梯度消失的情况?
Relu的优点
学习率太大太小会怎么样
大:不稳定的训练过程、容易错过最优解
小: 收敛速度慢、陷入局部最优解
Droput
随机失活
3.2 softmax、bs、归一化
Softmax函数
为什么Tanh收敛速度⽐Sigmoid快?——求导发现绝对值大
bs大和小的变化
小:batch数太小,而类别又比较多的时候,真的可能会导致loss函数震荡而不收敛
大:局部最小值,处理相同的数据量的速度越快,Batch_Size 增大到某个时候,达到时间上的最优
归一化作用
- 加快网络的训练和收敛的速度
- 控制梯度爆炸防止梯度消失
- 防止过拟合
类型
普通归一化,批量归一化(BN)、标准化
第四章 经典网络看另一篇笔记
第五章 深度学习神经网络
5.1 卷积神经网络
5.2 常规卷积、可分离卷积、深度可分离卷积、逐点卷积
可分离卷积(Separable convolution)详解-CSDN博客
可分离卷积包括空间可分离卷积(Spatially Separable Convolutions)和深度可分离卷积(depthwise separable convolution)。
假设feature的size为[channel, height , width]
空间也就是指:[height, width]这两维度组成的。
深度也就是指:channel这一维度。常规卷积
常规卷积
可分离卷积——空间可分离卷积+深度可分离卷积
Depthwise 卷积 ,Pointwise 卷积与普通卷积的区别-CSDN博客
分组卷积
depthwise卷积,只改变feature map的大小,不改变通道数。
Pointwise卷积,不改变feature map的大小,只改变通道数。
逐点卷积
深度可分离卷积=分组+逐点卷积
5.3 一维卷积、二维卷积、三位卷积有什么不同之处
其实就是尺寸发生了变化,其他的都一样的,一维只有一个维度,二维有两个维度kw,kh
5.4 池化的方式有几种
一般池化,重叠池化,SPP金字塔池化
5.5 1*1卷积的用处
1*1卷积核:由于1x1卷积核可以在不增加也不减少信息的情况下维持特征图的尺寸,加深度
5.6 怎样才能减少卷积层参数量
1 使用小卷积核替代大卷级
2 分离卷积操作
3 1*1卷积或者池化层
5.7 提⾼卷积神经⽹络的泛化能⼒
1 使用更多的数据
2 增大bs
3 调整数据的分布
4 数据增强
5 网络正则化
5.8 全连接、局部连接、全卷积与局部卷积
第六章 目标检测
6.0 数据集
coco数据集
COCO数据集介绍以及pycocotools简单使用_哔哩哔哩_bilibili
问题 object 80类和stuff 91类的区别有哪些?区别在哪?
目标检测用80类 stuff用的是91类
问题下载文件在哪?
为什么不需要测试级或者验证集?只有比赛怕作弊时候需要测试级。通常情况下不需要进行test的。
MS COCO数据集介绍以及pycocotools简单使用_ann_file='data/coco/annotations/instances_val2017.-CSDN博客
6.1 基本概念
目标检测解决什么问题?
计算机视觉4个任务:分类——解决是什么问题;定位——解决在哪里的问题;
因此检测——分类+定位
单个阶段的主要是yolo和ssd
二阶段检测网络
Rnn
backbone都是VGG16
候选框的归纳
思路就是候选框(先验框)变成预测框,然后根据损失函数变成真实框
FastRCNN
不太一样的地方:
1、rcnn值得是将ss算法的图像直接输入到网络上面。fastrcnn直接是把图像映射到整个图像的特征上取整个图像特征的一部分。这样不需要重复计算重复地方
2、rcnn全连接层那块的是一个是fc(坐标点),一个是svm(分类),fastrcnn两个都是fc可以同时训练
3、rcnn输入图像是227*227 ,但是fastrcnn不要求只是特征图最后变成7*7,通过Rol进行pooling计算(意思就是rol规定为7*7输出的情况,rol'本身指的是候选框意思)输出的维度指的是bs*channel*w*h(bs等于rol的数目)
注意:
训练时候不是直接把图片输入,而是采样进行计算
分类器
回归器的个数节点
边界框回归器
损失函数
分类损失就是交叉墒,边界框就是回归损失(smooth loss类似MAE)
FasterRCNN
一文读懂Faster RCNN(大白话,超详细解析)-CSDN博客
和前面不同的在于:把ss算法换成了PRN
为什么不直接预测修正后的anchor坐标,而是预测偏移量?
直接预测框坐标,数量级比较大,难以训练
xa指的是archor的坐标
RPN详细:对于每一个的特征原点我们生成k个候选框(anchor box),对于每一个候选框生成4个坐标回归。这个k的数量其实就是3*3=9
cls一个是背景一个是物体的概率。reg表示的是回归的类型,输出的四个点坐标
候选框的设置
感受野可以比原始图像尺寸大一点。
候选框如何进行筛选的呢?——先进行图片所说的,然后对候选框进行采样
RPN的总结
损失函数指的是softmax cross entropy 分类损失指的是二分类,每个框进行二元损失判断前景还是后景。对于回归任务我们采用的是smooth loss类似MAE。相当于分成两个部分,一部分RPN指的是前景后景+回归框,另一部分指的是检测网络里面的
对于训练方式:联合训练,以前原版是分开训练。
具体网络结构
rol pooling的如何做的
如何训练的
FPN网络
就是映射不一样的,第一次的两个函数是根据p2-p6计算的,第二个fsterrcnn是p2-p5里面计算的
在fpn网络里面32*32里面的 对应的是P2这个,其他以此类推,只看面积不看比例大小的,映射到对应的特征图。
sppnet网络
SPP-Net是一种可以不用考虑图像大小,输出图像固定长度的网络结构,并且可以做到在图像变形情况下表现稳定。
SPP、ROI Pooling、ROI Align区别
SPP、ROI Pooling、ROI Align区别_roi与spp的区别-CSDN博客
spp改变的是21(1+4+16)
ROI Pooling改变的是映射条件,例如 映射到68*68的地方,然后如何变成7*7呢?就是68/7里面的距离双线性插值为一个位置就可以
单阶段的目标检测网络
ssd算法
1)基于区域的算法: RCNN, Fast RCNN, Faster RCNN, Mask RCNN 等。整个检测过程分为两个阶段。在第一个阶段,检测器需要找到一些假设的区域 (ROI);在第二个阶段,检测器需要在这些假设区域上进行分类 (classification) 和 位置回归 (bounding box regression)。
2)基于回归的算法:YOLO系列 等。检测是一个端到端 (end-to-end) 的过程,直接回归出物体的类别和位置。
SSD(Single Shot MultiBox Detector)是一个one stage的检测算法。它可以认为是 Faster RCNN 和 YOLO 的结合:采用了基于回归的模式(类似于YOLO),在一个网络中直接回归出物体的类别和位置,因此检测速度很快。同时也利用了基于区域的概念(类似于Faster RCNN),在检测的过程中,使用了许多候选区域作为ROI。
bakbone vgg16
网络结构设置
大的特征图会预测小的图像,小的尺寸特征图会预测大的图像
预测回归的返回参数:
ck+4k c是类别数数目+1(样本包括一个前景) k是框的数目,是6个特征层夹在一起的那种
正负样本的选取
SSD算法解析-CSDN博客(具体看这个)
SSD的损失函数和Faster RCNN中的损失函数基本一致,它包括位置损失( loc)与类别置信度损失(conf)的加权和
EifficientNet网络_B0——基本的分类网络
width和depth和分辨率都会得到更好的结果,需要把她们结合一下
depth会丰富,但是深会造成梯度消失
width会得到更好的特征,容易训练,但深度低下(卷积核大)
Efficientnet网络详解及构建_efficient网络-CSDN博客
网络结构
MBConv
SE模块
effienctnet网络
其实就是两个发生了变化
backbone还是原来的
对于融合来说发生的变化是:1、concant变成了add2、融合的方式不太一样了
第七章 分割任务
7.0基本知识点
标注工具:label+SIseg分割标注软件
第八章 强化学习
8.1 基本概念
State可以理解成状态(环境状态) reward奖励,agent处的状态得到下一步的动作,根据动作得到环境的影响
policy
return 回报 指的是现在的回报加上以后的
1 回报是所有的时刻的,不是一个时刻的
2 存在的一个折扣率的
两个价值函数
Qπ 一种是动作价值函数,它主要和policy函数π有关,和状态s和动作a有关,它是Ut的条件期望,这里的Ut是个随机变量,它等于未来所有奖励的加权求和,期望把未来的动作和状态都消除了,只留下St和At这两个变量。Qπ说明agent处在状态s时做出动作a是否明智,Qπ可以给动作a打分。
Vπ 状态价值函数,Vπ是把Qπ中的变量A用积分去掉,这样变量就只剩下状态s,Vπ跟policy函数π和状态s有关和动作a无关。如果使用policy函数π,那么Vπ能够评价当前状况是好是坏,我们是快赢了还是其它。如果π是固定的那么状态s越好Vπ的数值就越大
8.2 实际例子
Q-Learning
import numpy as np
# 环境参数(需要根据您的环境进行调整)
state_space_size = 100 # 假设状态空间大小为100
action_space_size = 10 # 假设动作空间大小为10
initial_state = 0 # 初始状态
# 初始化 Q 表
Q = np.zeros((state_space_size, action_space_size))
# 学习参数
alpha = 0.1 # 学习率
gamma = 0.99 # 折扣因子
epsilon = 0.1 # 探索率
num_episodes = 1000 # 训练回合数
# Q-learning 训练过程
for episode in range(num_episodes):
current_state = initial_state
done = False
while not done:
# Epsilon-贪婪策略选择动作
if np.random.uniform(0, 1) < epsilon:
action = np.random.randint(0, action_space_size)
else:
action = np.argmax(Q[current_state])
# 执行动作并获取反馈
next_state, reward, done = take_action(current_state, action)
# 更新 Q 表
Q[current_state, action] = Q[current_state, action] + alpha * (
reward + gamma * np.max(Q[next_state]) - Q[current_state, action])
current_state = next_state
# Q 表训练完毕,可以用于指导决策
take action
def take_action(state, action):
"""
对于给定的状态和动作,返回下一个状态、奖励和是否结束。
参数:
state (int): 当前状态。
action (int): 执行的动作。
返回:
next_state (int): 下一个状态。
reward (float): 因动作获得的奖励。
done (bool): 游戏是否结束。
"""
# 假设迷宫大小为10x10
maze_size = 10
# 将线性状态转换为二维坐标
x, y = state % maze_size, state // maze_size
# 定义动作
# 0: 上, 1: 右, 2: 下, 3: 左
if action == 0 and y > 0:
y -= 1
elif action == 1 and x < maze_size - 1:
x += 1
elif action == 2 and y < maze_size - 1:
y += 1
elif action == 3 and x > 0:
x -= 1
# 计算下一个状态
next_state = y * maze_size + x
# 定义奖励和游戏结束条件
reward = 0
done = False
if next_state == maze_size * maze_size - 1: # 假设目标是到达迷宫的右下角
reward = 1 # 到达目标奖励
done = True
return next_state, reward, done
ddpg
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
# 假设状态空间和动作空间的大小
state_space_size = 4 # 例如:状态空间大小为4
action_space_size = 2 # 例如:动作空间大小为2
# 创建一个简单的 Actor 神经网络
actor = Sequential()
actor.add(Dense(32, input_dim=state_space_size, activation='relu'))
actor.add(Dense(32, activation='relu'))
actor.add(Dense(action_space_size, activation='tanh')) # 使用tanh激活函数以输出在[-1, 1]范围的动作值
# 假设这里我们已经有了一个训练好的模型
# actor.load_weights('path_to_your_saved_model.h5')
# 当前环境状态的示例(通常从你的环境中获取)
current_state = np.random.rand(state_space_size) # 创建一个模拟的随机状态
current_state = current_state.reshape(1, -1) # 调整形状以匹配网络输入
# 使用actor模型来预测动作
predicted_action = actor.predict(current_state)
# 输出预测的动作
print("Predicted Action:", predicted_action)
7个最流行的强化学习算法实战案例(附 Python 代码)_强化学习案例-CSDN博客
都是更新action state等
第九章 迁移学习
迁移学习(Transfer)-CSDN博客 可以看看23点
附页
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))
几个问题?
如何提高:
1 、可以像BIGGan进行改进 2、多生成几个GENerator 一种集成思想。
Gan网络崩溃
怎么办呢?
1 归一化图像,使用最后一层tanh
2 不要在均匀分布上采样,应该在⾼斯分布上采样
3 Generator使⽤Adam,Discriminator使⽤SGD
4 如果有标签,请尽量利⽤标签信息来训练
5 如果可以,请⽤DCGAN或者混合模型:KL+GAN,VAE+GAN。
6 尽快发现错误;⽐如:判别器Loss为0,说明训练失败了;如果⽣成器Loss稳步下降,说明判别器没发挥作⽤
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 ⽆监督图像翻译:CycleGAN
7 自编码器
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层我们需要考虑窗口移动与自注意编码
4 MobileViT
MobileViT模型简介_mobilevitattention-CSDN博客
以往训练的困难:
1、Transformer缺少空间归纳偏置,图像的空间信息很重要,迁移到别的任务会导致有问题,都是固定的分辨率,别的任务可能信息位置和分辨率都存在问题
2、迁移到其他任务(输入图像分辨率发生改变)时比较繁琐,分辨率在cnn上会涨点,但是在transfomer上面可能就不会
3、transformer的训练更加困难。需要更多数据
网络结构
MV2的结构
moblieVIt
具体如何进行unfold呢?
意思就是相隔某几个元素进行self-attention
16 RNN与LSTM
如何从RNN起步,一步一步通俗理解LSTM_rnn lstm-CSDN博客
1 RNN
RNN基本原理
为了解决文字语言的:序列形的数据就不太好用原始的神经网络处理了,引入了隐状态h(hidden state)的概念,隐状态h可以对序列形的数据提取特征,接着再转换为输出。
Encoder-Decoder结构
对于Encoder来说
主要类别
RNN与CNN区别
为什么RNN 训练的时候Loss波动很⼤
Attention
其实就是h1、h2、h3、h4得到的a。然后根据根据h2'修改a
2 LSTM
本质:
σ表示的Sigmoid 激活函数与 tanh 函数类似,不同之处在于 sigmoid 是把值压缩到0~1 之间而不是 -1~1 之间。这样的设置有助于更新或忘记信息:
因为任何数乘以 0 都得 0,这部分信息就会剔除掉;
同样的,任何数乘以 1 都得到它本身,这部分信息就会完美地保存下来。
LSTM核心
忘记门
输入门
细胞状态
输出门——最关键
RNN在NLP翻译中的应用
1 语音模型和文本生成
2 机器翻译
3 语音识别
4 图像描述⽣成
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个维度如下图所示:
和fasterrnn很相似的,都是特征图进行预测的。不是原始图像,但是fastrcnn和rcnn都是原图通过传统算法得到区域直接进行回归和分类
和fasterrcnn相比较,yolo类似faster里面说3*3个候选框,yolo1是2个候选框
- 每个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 如果没有物体的也需要损失函数
非极大值抑制:选取最大的最好的那个置信度
4 为什么位置误差开根号:为了使得大目标偏差和小目标偏差差不多会这样。但还是没有解决这个问题。
问题
小问题一般化
2 yolo2 检测
Draknet19
深度学习目标检测_YOLOV2超详细解读_yolov2结构图-CSDN博客
此外预测方式也发生了改变
第一个:为什么输入是416?为什么是400+,不是224呢,因为这样可以让图片分辨率更好
因为2^5可以把416整除这样的话。此外因为:
第二个 网络图很像VGG16所以,而且没有线性层,最后一层conv很特殊
第三个先验框的提取 聚类的方法,采用的iou面积来计算的
通过计算选取不同的先验框来计算原先是9个 使用了archor-base(第一次使用)没有使用archor-free
有一个问题?为什么可以取
第四个怎么预测的?
V2中没有使用偏移量,而是选择相对gride cell 的偏移量。
把每一个格子看成1来计算的,且看的是相对于左上角的
这个tx,ty很大程度指的是中间的方块进行计算的所以直接就是sigomid计算出来的
第五个问题?如何训练的
anchor卷积操作
3 yolo3 检测
网络:
主干网络是deaknet53
输出信息类别
4个偏移参数+置信度+边框坐标就是特征图大小的(13*13+26*26+52*52)
总结一下
yolo1——box(7*7*2)——输出特征是7*7*(5+5+20)
yolo2——box(13*13*3*3)9个先眼框——输出特征是13*13*(5+20)*9
yolo3——box(13*13*3+26*26*3+52*52*3)9个先眼框——输出特征是(13*13*3+26*26*3+52*52*3)*(5+20)
yolov4和yolov3一样的
所谓的多尺度就是来自这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的运用
损失函数的计算
两个类别都是sgmoid的
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本身指的是13*3*5*5——变成了13*42(13*3*1*1+13*3*2*2+13*3*3*3),但是在yolov里面好像是把直接池化了。
SPP(Spatial Pyramid Pooling)解读_spp结构-CSDN博客
FAN
1 加一起变成拼接,原来的是add+的操作,这个里面说concat的操作
好处:
引入了自底向上的路径,使得底层信息更容易传到顶部
并且还是一个捷径,红色的没准走个100层(Resnet),绿色的几层就到了
总结:
backbone改变了
conv的一部分用mish改变
下采样采用了SPP
消除敏感度为了防止出现边界情况相当于直接把函数进行了平移,平移0时候x趋近于负无穷
提出了空间注意力机制
focalloss
yolo的候选框太多了,红色的框都是负样本,就是负样本太多了
5 yolo5 检测
YOLOv5网络详解_yolov5网络结构详解-CSDN博客
对于backbone来说yolo2就是darknet19 yolov3指的是darknet53,yolov4指的是darknet53-csp
yolov5指的是darknet53-new
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 操作
focus 就是卷积
自适应框选
自适应图片缩放
YOLOv5 提出一种方法能够自适应的添加最少的黑边到缩放之后的图片
focus
残差网络有两种
YOLOv5网络模型的结构原理讲解(全)_yolov5网络结构详解-CSDN博客
SPP变成SPPF
相当于实现的效率更高了
损失函数——稍微注意一下
不同的size的分类损失函数也不一样的
最后改变了这样的
5 补充 yolox 检测
网络图
解耦头
6 yolo6 检测
1+1+1
YOLO v6:一个硬件友好的目标检测算法_解耦检测头-CSDN博客
YOLO系列详解:YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5、YOLOv6、YOLOv7-CSDN博客
YOLOv6 Pro | YOLOv6网络魔改 (1) ——RepGFPN融合高效聚合网络(ELAN)和重参数化的目标检测Neck(来自DAMO-YOLO)-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
代码:
backbone
from torch import nn
from yolov6.layers.common import RepVGGBlock, RepBlock, SimSPPF
import ipdb
class EfficientRep(nn.Module):
'''EfficientRep Backbone
EfficientRep is handcrafted by hardware-aware neural network design.
With rep-style struct, EfficientRep is friendly to high-computation hardware(e.g. GPU).
'''
def __init__(
self,
in_channels=3,
channels_list=None,
num_repeats=None,
block=RepVGGBlock
):
super().__init__()
assert channels_list is not None
assert num_repeats is not None
self.stem = block(
in_channels=in_channels,
out_channels=channels_list[0],
kernel_size=3,
stride=2
)
self.ERBlock_2 = nn.Sequential(
block(
in_channels=channels_list[0],
out_channels=channels_list[1],
kernel_size=3,
stride=2
),
RepBlock(
in_channels=channels_list[1],
out_channels=channels_list[1],
n=num_repeats[1],
block=block,
)
)
self.ERBlock_3 = nn.Sequential(
block(
in_channels=channels_list[1],
out_channels=channels_list[2],
kernel_size=3,
stride=2
),
RepBlock(
in_channels=channels_list[2],
out_channels=channels_list[2],
n=num_repeats[2],
block=block,
)
)
self.ERBlock_4 = nn.Sequential(
block(
in_channels=channels_list[2],
out_channels=channels_list[3],
kernel_size=3,
stride=2
),
RepBlock(
in_channels=channels_list[3],
out_channels=channels_list[3],
n=num_repeats[3],
block=block,
)
)
self.ERBlock_5 = nn.Sequential(
block(
in_channels=channels_list[3],
out_channels=channels_list[4],
kernel_size=3,
stride=2,
),
RepBlock(
in_channels=channels_list[4],
out_channels=channels_list[4],
n=num_repeats[4],
block=block,
),
SimSPPF(
in_channels=channels_list[4],
out_channels=channels_list[4],
kernel_size=5
)
)
def forward(self, x):
# ipdb.set_trace()
outputs = []
x = self.stem(x) # 64*16*304*304
x = self.ERBlock_2(x) # 64*16*152*152
x = self.ERBlock_3(x)# 64*64*76*76
outputs.append(x)
x = self.ERBlock_4(x) # 64*128*38*38
outputs.append(x)
x = self.ERBlock_5(x) # 64*256*19*19
outputs.append(x)
return tuple(outputs)
neck输入的是tuple[ 64*64*76*76,64*128*38*38,64*256*19*19]
import torch
from torch import nn
from yolov6.layers.common import RepBlock, SimConv, Transpose, RepVGGBlock
class RepPANNeck(nn.Module):
"""RepPANNeck Module
EfficientRep is the default backbone of this model.
RepPANNeck has the balance of feature fusion ability and hardware efficiency.
"""
def __init__(
self,
channels_list=None,
num_repeats=None,
block=RepVGGBlock,
):
super().__init__()
assert channels_list is not None
assert num_repeats is not None
self.Rep_p4 = RepBlock(
in_channels=channels_list[3] + channels_list[5],
out_channels=channels_list[5],
n=num_repeats[5],
block=block
)
self.Rep_p3 = RepBlock(
in_channels=channels_list[2] + channels_list[6],
out_channels=channels_list[6],
n=num_repeats[6],
block=block
)
self.Rep_n3 = RepBlock(
in_channels=channels_list[6] + channels_list[7],
out_channels=channels_list[8],
n=num_repeats[7],
block=block
)
self.Rep_n4 = RepBlock(
in_channels=channels_list[5] + channels_list[9],
out_channels=channels_list[10],
n=num_repeats[8],
block=block
)
self.reduce_layer0 = SimConv(
in_channels=channels_list[4],
out_channels=channels_list[5],
kernel_size=1,
stride=1
)
self.upsample0 = Transpose(
in_channels=channels_list[5],
out_channels=channels_list[5],
)
self.reduce_layer1 = SimConv(
in_channels=channels_list[5],
out_channels=channels_list[6],
kernel_size=1,
stride=1
)
self.upsample1 = Transpose(
in_channels=channels_list[6],
out_channels=channels_list[6]
)
self.downsample2 = SimConv(
in_channels=channels_list[6],
out_channels=channels_list[7],
kernel_size=3,
stride=2
)
self.downsample1 = SimConv(
in_channels=channels_list[8],
out_channels=channels_list[9],
kernel_size=3,
stride=2
)
def forward(self, input):
(x2, x1, x0) = input
fpn_out0 = self.reduce_layer0(x0) #64*64*19*19
upsample_feat0 = self.upsample0(fpn_out0) # 64*64*38*38
f_concat_layer0 = torch.cat([upsample_feat0, x1], 1) #38*38结合一下
f_out0 = self.Rep_p4(f_concat_layer0) # 64*64*38*38
fpn_out1 = self.reduce_layer1(f_out0) # 64*64*38*38
upsample_feat1 = self.upsample1(fpn_out1) # 64*32*76*76 x2 64*64*76*76
f_concat_layer1 = torch.cat([upsample_feat1, x2], 1) # 64*96*76*76
pan_out2 = self.Rep_p3(f_concat_layer1) # 64*32*76*76
down_feat1 = self.downsample2(pan_out2)
p_concat_layer1 = torch.cat([down_feat1, fpn_out1], 1)
pan_out1 = self.Rep_n3(p_concat_layer1)
down_feat0 = self.downsample1(pan_out1)
p_concat_layer2 = torch.cat([down_feat0, fpn_out0], 1)
pan_out0 = self.Rep_n4(p_concat_layer2)
outputs = [pan_out2, pan_out1, pan_out0] # 64*32*76*76 64*64*38*38 64*128*19*19
return outputs
detect头部
输入就是outputs
class Detect(nn.Module):
'''Efficient Decoupled Head
With hardware-aware degisn, the decoupled head is optimized with
hybridchannels methods.
'''
def __init__(self, num_classes=80, anchors=1, num_layers=3, inplace=True, head_layers=None): # detection layer
super().__init__()
assert head_layers is not None
self.nc = num_classes # number of classes
self.no = num_classes + 5 # number of outputs per anchor
self.nl = num_layers # number of detection layers
if isinstance(anchors, (list, tuple)):
self.na = len(anchors[0]) // 2
else:
self.na = anchors
self.anchors = anchors
self.grid = [torch.zeros(1)] * num_layers
self.prior_prob = 1e-2
self.inplace = inplace
stride = [8, 16, 32] # strides computed during build
self.stride = torch.tensor(stride)
# Init decouple head
self.cls_convs = nn.ModuleList()
self.reg_convs = nn.ModuleList()
self.cls_preds = nn.ModuleList()
self.reg_preds = nn.ModuleList()
self.obj_preds = nn.ModuleList()
self.stems = nn.ModuleList()
# Efficient decoupled head layers
for i in range(num_layers):
idx = i*6
self.stems.append(head_layers[idx])
self.cls_convs.append(head_layers[idx+1])
self.reg_convs.append(head_layers[idx+2])
self.cls_preds.append(head_layers[idx+3])
self.reg_preds.append(head_layers[idx+4])
self.obj_preds.append(head_layers[idx+5])
def initialize_biases(self):
for conv in self.cls_preds:
b = conv.bias.view(self.na, -1)
b.data.fill_(-math.log((1 - self.prior_prob) / self.prior_prob))
conv.bias = torch.nn.Parameter(b.view(-1), requires_grad=True)
for conv in self.obj_preds:
b = conv.bias.view(self.na, -1)
b.data.fill_(-math.log((1 - self.prior_prob) / self.prior_prob))
conv.bias = torch.nn.Parameter(b.view(-1), requires_grad=True)
def forward(self, x):
z = []
# ipdb.set_trace()
for i in range(self.nl):
x[i] = self.stems[i](x[i])
cls_x = x[i]
reg_x = x[i]
cls_feat = self.cls_convs[i](cls_x)
cls_output = self.cls_preds[i](cls_feat) # 64*2*76*76(因为有两类)
reg_feat = self.reg_convs[i](reg_x)
reg_output = self.reg_preds[i](reg_feat) # 64*4*76*76
obj_output = self.obj_preds[i](reg_feat) # 64*1*76*76
if self.training:
x[i] = torch.cat([reg_output, obj_output, cls_output], 1)
bs, _, ny, nx = x[i].shape
na=self.na
no=self.no
x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous()
#0: 64*1*76*76*7 1 64*1*38*38*7 2 64*1*19*19*7
loss计算
class ComputeLoss:
'''Loss computation func.
This func contains SimOTA and siou loss.
'''
def __init__(self,
reg_weight=5.0,
iou_weight=3.0,
cls_weight=1.0,
center_radius=2.5,
eps=1e-7,
in_channels=[256, 512, 1024],
strides=[8, 16, 32],
n_anchors=1,
iou_type='ciou'
):
self.reg_weight = reg_weight
self.iou_weight = iou_weight
self.cls_weight = cls_weight
self.center_radius = center_radius
self.eps = eps
self.n_anchors = n_anchors
self.strides = strides
self.grids = [torch.zeros(1)] * len(in_channels)
# Define criteria
self.l1_loss = nn.L1Loss(reduction="none")
self.bcewithlog_loss = nn.BCEWithLogitsLoss(reduction="none")
self.iou_loss = IOUloss(iou_type=iou_type, reduction="none")
def __call__(
self,
outputs,
targets
):
# outputs:[64*1*76*76*7,64*1*38*38*7,64*1*19*19*7] targets (64*6)
dtype = outputs[0].type()
device = targets.device
loss_cls, loss_obj, loss_iou, loss_l1 = torch.zeros(1, device=device), torch.zeros(1, device=device), \
torch.zeros(1, device=device), torch.zeros(1, device=device)
num_classes = outputs[0].shape[-1] - 5
# 处理YOLOv6模型的输出,并为后续的边界框解码准备必要的信息。该方法主要执行以下步骤将测试出来的结果直接映射到检测框
outputs, outputs_origin, gt_bboxes_scale, xy_shifts, expanded_strides = self.get_outputs_and_grids(
outputs, self.strides, dtype, device)
total_num_anchors = outputs.shape[1]
bbox_preds = outputs[:, :, :4] # [batch, n_anchors_all, 4]
bbox_preds_org = outputs_origin[:, :, :4] # [batch, n_anchors_all, 4]
obj_preds = outputs[:, :, 4].unsqueeze(-1) # [batch, n_anchors_all, 1]
cls_preds = outputs[:, :, 5:] # [batch, n_anchors_all, n_cls]
# targets
# 这段代码负责处理目标(ground truth)数据以适配模型输出,并为损失计算准备必要的信息
# 确保目标数据与模型输出对齐,从而使损失函数能够有效地计算损失值
batch_size = bbox_preds.shape[0]
targets_list = np.zeros((batch_size, 1, 5)).tolist()
for i, item in enumerate(targets.cpu().numpy().tolist()):
targets_list[int(item[0])].append(item[1:])
max_len = max((len(l) for l in targets_list))
targets = torch.from_numpy(np.array(list(map(lambda l:l + [[-1,0,0,0,0]]*(max_len - len(l)), targets_list)))[:,1:,:]).to(targets.device)
num_targets_list = (targets.sum(dim=2) > 0).sum(dim=1) # number of objects
num_fg, num_gts = 0, 0
cls_targets, reg_targets, l1_targets, obj_targets, fg_masks = [], [], [], [], []
for batch_idx in range(batch_size):
num_gt = int(num_targets_list[batch_idx])
num_gts += num_gt
if num_gt == 0:
cls_target = outputs.new_zeros((0, num_classes))
reg_target = outputs.new_zeros((0, 4))
l1_target = outputs.new_zeros((0, 4))
obj_target = outputs.new_zeros((total_num_anchors, 1))
fg_mask = outputs.new_zeros(total_num_anchors).bool()
else:
gt_bboxes_per_image = targets[batch_idx, :num_gt, 1:5].mul_(gt_bboxes_scale)
gt_classes = targets[batch_idx, :num_gt, 0]
bboxes_preds_per_image = bbox_preds[batch_idx]
cls_preds_per_image = cls_preds[batch_idx]
obj_preds_per_image = obj_preds[batch_idx]
# 中用于为每个真实目标(ground truth)分配对应的预测的关键部分。
try:
(
gt_matched_classes,
fg_mask,
pred_ious_this_matching,
matched_gt_inds,
num_fg_img,
) = self.get_assignments(
batch_idx,
num_gt,
total_num_anchors,
gt_bboxes_per_image,
gt_classes,
bboxes_preds_per_image,
cls_preds_per_image,
obj_preds_per_image,
expanded_strides,
xy_shifts,
num_classes
)
except RuntimeError:
print(
"OOM RuntimeError is raised due to the huge memory cost during label assignment. \
CPU mode is applied in this batch. If you want to avoid this issue, \
try to reduce the batch size or image size."
)
torch.cuda.empty_cache()
print("------------CPU Mode for This Batch-------------")
_gt_bboxes_per_image = gt_bboxes_per_image.cpu().float()
_gt_classes = gt_classes.cpu().float()
_bboxes_preds_per_image = bboxes_preds_per_image.cpu().float()
_cls_preds_per_image = cls_preds_per_image.cpu().float()
_obj_preds_per_image = obj_preds_per_image.cpu().float()
_expanded_strides = expanded_strides.cpu().float()
_xy_shifts = xy_shifts.cpu()
# 这个方法返回以下几个元素:
#
# num_fg:
#
# 前景目标的数量。这是指在所有预测中被识别为包含真实对象的预测框的数量。前景目标通常是那些与真实标有高度重叠的预测框。
# gt_matched_classes:
#
# 匹配到的真实类别。对于每个前景预测框,此列表包含它所匹配的真实目标的类别。这有助于在计算分类损失时,将预测的类别与真实的类别进行对比。
# pred_ious_this_matching:
#
# 匹配预测的 IOU(交并比)。这是一个列表,包含每个前景预测框与其匹配的真实目标之间的交并比。IOU 是评估预测边界框准确性的关键指标。
# matched_gt_inds:
#
# 匹配的真实目标索引。这是一个索引列表,指出每个前景预测框对应于哪个真实目标。这有助于在计算回归损失时,将预测的边界框与真实的边界框进行对比。
# fg_mask:
#
# 前景掩码。这是一个布尔数组,指示每个预测框是否被视为前景(即包含真实目标)。这在损失计算中用于区分前景和背景预测框。
(
gt_matched_classes,
fg_mask,
pred_ious_this_matching,
matched_gt_inds,
num_fg_img,
) = self.get_assignments(
batch_idx,
num_gt,
total_num_anchors,
_gt_bboxes_per_image,
_gt_classes,
_bboxes_preds_per_image,
_cls_preds_per_image,
_obj_preds_per_image,
_expanded_strides,
_xy_shifts,
num_classes
)
gt_matched_classes = gt_matched_classes.cuda()
fg_mask = fg_mask.cuda()
pred_ious_this_matching = pred_ious_this_matching.cuda()
matched_gt_inds = matched_gt_inds.cuda()
先进行准备 给k动态分布进行准备情况
下面这部分是接着的
torch.cuda.empty_cache()
num_fg += num_fg_img
if num_fg_img > 0:
cls_target = F.one_hot(
gt_matched_classes.to(torch.int64), num_classes
) * pred_ious_this_matching.unsqueeze(-1)
obj_target = fg_mask.unsqueeze(-1)
reg_target = gt_bboxes_per_image[matched_gt_inds]
l1_target = self.get_l1_target(
outputs.new_zeros((num_fg_img, 4)),
gt_bboxes_per_image[matched_gt_inds],
expanded_strides[0][fg_mask],
xy_shifts=xy_shifts[0][fg_mask],
)
cls_targets.append(cls_target)
reg_targets.append(reg_target)
obj_targets.append(obj_target)
l1_targets.append(l1_target)
fg_masks.append(fg_mask)
cls_targets = torch.cat(cls_targets, 0)
reg_targets = torch.cat(reg_targets, 0)
obj_targets = torch.cat(obj_targets, 0)
l1_targets = torch.cat(l1_targets, 0)
fg_masks = torch.cat(fg_masks, 0)
num_fg = max(num_fg, 1)
# loss
loss_iou += (self.iou_loss(bbox_preds.view(-1, 4)[fg_masks].T, reg_targets)).sum() / num_fg
loss_l1 += (self.l1_loss(bbox_preds_org.view(-1, 4)[fg_masks], l1_targets)).sum() / num_fg
#if 'nan' in str(loss_iou):··
#ipdb.set_trace()
#(self.iou_loss(bbox_preds.view(-1, 4)[fg_masks].T, reg_targets)).sum() / num_fg
loss_obj += (self.bcewithlog_loss(obj_preds.view(-1, 1), obj_targets*1.0)).sum() / num_fg
loss_cls += (self.bcewithlog_loss(cls_preds.view(-1, num_classes)[fg_masks], cls_targets)).sum() / num_fg
total_losses = self.reg_weight * loss_iou + loss_l1 + loss_obj + loss_cls
return total_losses, torch.cat((self.reg_weight * loss_iou, loss_l1, loss_obj, loss_cls)).detach()
检测头部
基于yolox改进得到的
在 YOLOv6 中,我们采用了解耦检测头(Decoupled Head)结构,并对其进行了精简设计。原始 YOLOv5 的检测头是通过分类和回归分支融合共享的方式来实现的,而 YOLOX 的检测头则是将分类和回归分支进行解耦,同时新增了两个额外的 3x3 的卷积层,虽然提升了检测精度,但一定程度上增加了网络延时。
因此,我们对解耦头进行了精简设计,同时综合考虑到相关算子表征能力和硬件上计算开销这两者的平衡,采用 Hybrid Channels 策略重新设计了一个更高效的解耦头结构,在维持精度的同时降低了延时,缓解了解耦头中 3x3 卷积带来的额外延时开销。通过在 nano 尺寸模型上进行消融实验,对比相同通道数的解耦头结构,精度提升 0.2% AP 的同时,速度提升6.8%。
他这个输入的是neck的输出可以看一下代码,不是hwc
SIOU损失函数
目标检测--边框回归损失函数SIoU原理详解及代码实现_边框损失函数-CSDN博客
simOTA 细节学习
目标检测标签分配之 OTA 和 SimOTA 细节学习-CSDN博客
首先是3*1000 3个物体 1000个候选框
选取前十个进行当成正样本
正样本加一起得到一个值 文中里面的是 343
然后进行选取最大的当成正样本
速度快,但是效果低了
k动态分配的方法对每张图片进行匹配
(
gt_matched_classes,
fg_mask,
pred_ious_this_matching,
matched_gt_inds,
num_fg_img,
) = self.get_assignments(
batch_idx,
num_gt,
total_num_anchors,
_gt_bboxes_per_image,
_gt_classes,
_bboxes_preds_per_image,
_cls_preds_per_image,
_obj_preds_per_image,
_expanded_strides,
_xy_shifts,
num_classes
)
7 yolo7 检测
给一个结构图看吧 up不写了太累了
补充知识点:检测指标知识点
目标检测评价指标-CSDN博客【语义分割】评价指标:PA、CPA、MPA、IoU、MIoU详细总结和代码实现_语义分割mpa计算公式-CSDN博客目标检测评价指标-CSDN博客
9 RGB-T检测
论文解读:跨模态/多光谱/多模态检测 Cross-Modality Fusion Transformer for Multispectral Object Detection-CSDN博客
10 跟踪算法
CenterTrack改进:替换主干网络为Ghostnet-CSDN博客
【Anchor Free】CenterNet的详细解析 - 知乎
【Anchor free】CornerNet 网络结构深度解析(全网最详细!) - 知乎
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博客
4 mask-rcnn
Mask R-CNN网络详解_mask rcnn详解-CSDN博客
涉及一个问题就是新的RoI Align 比RoIPool相比好在哪
5 FCN
分割最初模型
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 注意力机制
3 Grad_CAM
23 资源说明
https://download.csdn.net/download/ydp15755423176/88747203
第七章开始有一点特色需要注意的
5 可视化结果
7 模型读取与构建
包括情况是:模型存储+模型单卡存储多卡储存+单卡保存多卡加载+多卡保存多卡加载
如何单卡变成多卡?
import os
import argparse
import torch
from my_model import MyModel # 假设 MyModel 是您的模型类
parser = argparse.ArgumentParser()
parser.add_argument('--gpu', default='0', type=str,
help='gpu device ids for CUDA_VISIBLE_DEVICES, separated by comma')
args = parser.parse_args()
# 设置 CUDA_VISIBLE_DEVICES
os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu
# 其他参数和模型初始化
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = MyModel(...)
if torch.cuda.device_count() > 1:
print("Using", torch.cuda.device_count(), "GPUs for training.")
model = torch.nn.DataParallel(model)
model.to(device)
# 之后是您的训练循环
9 模型微调
torchvision微调+timm读取模型数据(感觉和部分torch库差不多)+半精度训练
timm不介绍,里面写的就是模型调用和名称
半精度训练就是把32浮点数变成16浮点数
10 模型推理与部署
得到模型与权重+倒出onnx模型并验证+直接可视化
具体内容可以参考可视化界面
24 相机标定
1 双目相机
opencv双目标定原理_双目相机标定以及立体测距原理及OpenCV实现-CSDN博客
一文讲透鱼眼相机畸变矫正,及目标检测项目应用 值得收藏_verilog鱼眼矫正-CSDN博客
标定的意思就是拍摄图片和实际图片的差异,在图片输入时候进行修改什么的
2 单目相机
3 深度相机
双目、结构光、tof,三种深度相机的原理区别看这一篇就够了!_深度相机和双目相机区别-CSDN博客
双目相机属于深度相机的一种形式
25 深度估计
附加一些小问题
面试经验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
Anchor based and Anchor free(无锚VS有锚)【总结】_anchorbased和anchorfree-CSDN博客
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博客
1 如果有m个目标,先进行极大值抑制然后进行赛选出m个框
2 根据不同的置信度得到不同的查准率和查全率,根据iou的不同会使得框的数量发生变化,主要是看不同的iou计算的
3 得到pr时候画出图,把不同iou下的ap取平均就是map
iou越大定位越准确
项目的数据增强手段
融合图像不存在数据增强,行人重识别存在
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。适合多分类问题。
耦合头 与 解耦头:
实验表明,将耦合头替换为解耦头大大提高了收敛速度,而解耦合头对于端到端版本的YOLO至关重要
总结
简单来说,解耦合头突出在一个解字,就是把特征图用不同的分支分开处理,而耦合头不分开 一起处理了。
常见的解耦合头设计包括Faster R-CNN中的RPN(Region Proposal Network)和 Fast R-CNN中的RoI Pooling。
Ycbcr<——>RGB:
正负样本对目标检测算法影响
正负样本划分是在训练集上面,nms是在测试集合上面,正负样本划分是为了损失含糊,正样本进行回归+分类任务,负样本进行分类前景和后景的区别,nms选择的是多少个目标框。
【目标检测】58、目标检测中的正负样本分配策略总结-CSDN博客(每个网络情况不太一样)
1、负样本:在目标检测任务中,数据集中部分图片没有出现目标,这些图片通常被称为负样本。
正样本:指包含目标的图像。
背景:背景是指整个图像中不包含目标的区域,它与负样本不同。负样本是针对整个图片而言,背景是针对边界框而言。
2、问题如果负样本的图片过多,会学习错误,但是大模型可以有很好的泛化性能。如果过少会导致失去鲁棒性
3、剔除测试集的负样本,评价指标变差?因为测试机和训练集的样本分布不太一样
4、正负样本平衡的方法:
算法调整问题——目标检测中的不平衡问题。
https://blog.csdn.net/jiaoyangwm/category_10899327.html
focalloss
其实就是概率越大越容易被发现,现在难以分辨的概率肯定小一点,这样r》1时候更容易把难区别的分别出来
Focal Loss特点:
当很小时(样本难分,不管分的是否正确),调节因子趋近1,损失函数中样本的权重不受影响;当很大时(样本易分,不管分的是否正确),调节因子趋近0,损失函数中样本的权重下降很多
聚焦参数可以调节易分类样本权重的降低程度,越大权重降低程度越大
通过分析Focal Loss函数的特点可知,该损失函数降低了易分类样本的权重,聚焦在难分类样本上。
raw图片有什么优势
为什么要进行warmup
wp主要是说训练开始的阶段逐渐增加学习率的过程
1 避免一开始就梯度爆炸刚开始用较小的学习率
2 增加学习率更好的探索空间,找到局部最小值
3 可以提高模型性能和训练稳定性的技巧
GradScaler 有什么作用吗
为什么使用这个?
-
防止梯度下溢(其实就是0):在使用 float16 进行计算时,非常小的梯度值可能会变成零(下溢),导致模型训练过程中丢失重要信息。
GradScaler
通过缩放梯度值来减少这种风险。 -
保持数值稳定性:在 float16 计算中,
GradScaler
帮助维持数值的稳定性,特别是在执行一些可能导致数值不稳定的操作(如除法、大数和小数的运算)时。
这里面涉及一个梯度积累的知识点:
小目标检测的影响
面试经验5
1. 多态的实现方式
C++中的多态主要通过虚函数(virtual
函数)实现。有两种形式的多态:
- 编译时多态:也称为静态多态,主要通过函数重载和模板实现。
- 运行时多态:也称为动态多态,通过虚函数和继承实现。当你在基类中声明一个函数为
virtual
,并在派生类中重写该函数时,会根据对象的实际类型来调用相应的函数,即使是通过基类的指针或引用。
2. shared_ptr
和 unique_ptr
的区别
unique_ptr
:表示对某个资源的独占拥有权。一个unique_ptr
对象在任何时刻都只能被一个所有者拥有,这意味着不能复制unique_ptr
,但可以移动其所有权。shared_ptr
:允许多个所有者共享同一资源。通过内部使用引用计数机制,当最后一个shared_ptr
被销毁时,资源会被自动释放。shared_ptr
可以被复制和移动,复制时引用计数增加,移动时不改变引用计数。
3. const
关键字的用途
const
关键字可以用来修饰变量、指针、函数参数、函数返回值、成员函数等,表示它们是不可修改的:
- 修饰变量:表明该变量的值不可改变。
- 修饰指针:可以是指向常量的指针,或者是常量指针,或两者兼有。
- 修饰函数参数:表明参数在函数内不可被修改,可以用于引用和指针,提高安全性和效率。
- 修饰函数返回值:防止返回值被错误地修改。
- 修饰成员函数:表明该成员函数内不会修改任何成员变量,可以在常对象上调用。
4. C++11 的新特性
我已经在之前的回答中详细描述了 C++11 的主要新特性,包括自动类型推导 (auto
)、基于范围的 for
循环、Lambda 表达式、右值引用和移动语义、nullptr
、常量表达式 (constexpr
)、统一的初始化列表、委托构造函数、显式虚函数重载 (override
和 final
)、强类型枚举 (enum class
)、多线程支持、智能指针等。
5. extern "C"
的作用
extern "C"
用于在 C++ 代码中声明 C 函数或代码块,告诉编译器这部分代码使用 C 的链接约定。这是为了解决 C++ 因名称修饰(name mangling)导致的函数重载与 C 语言链接不兼容的问题,使得 C++ 程序可以调用 C 语言编写的库。
6. 定义父类时析构函数声明的注意事项
当定义一个父类时,如果这个类会被其他类继承,那么它的析构函数应该声明为 virtual
。这样做是为了确保当通过基类指针删除一个派生类对象时,能够正确地调用派生类的析构函数,然后是基类的析构函数,从而正确地释放资源。如果基类的析构函数不是 virtual
的,那么删除派生类对象可能只会调用基类的析构函数,导致资源泄露或其他未定义行为。
7 量化层与非量化层的关系
量化指的是32浮点数变成8浮点数的意思,反量化意思就是相反的
8 .raw文件的作用
9 Netron 直接进去然后拖入onnx文件即可修改
权限限制用这个
解决:mkdir: cannot create directory ‘test’: Permission denied-CSDN博客
10 argc 和argv区别是什么
10 # ifend与# endif 用法
10 deepsort里面的两个创新
第一个指的是当前真匹配到最合适的进行追踪,第二个指的是匹配到==帧数和以前目标的iou计算