引言
- 深度学习的基础知识查漏补缺以及高频面试题
深度学习基础
基本概念
为什么使用深层表示
- 深度神经网络是一种特征递进式的学习方法, 浅层神经元学习低层次的简单特征, 深层的特征基于以学习到的浅层特征继续学习更高级的特征
- 深层的网络隐藏单元数量相对较少, 隐藏层数目较多, 若浅层的网络想达到相同的计算结果需要指数级增长的单元数量
神经网络更深的意义
- 前提: 一定范围内
- 在神经元数量相同的情况下, 深层网络结构具有更大容量, 分层组合带来的是指数级的表达空间, 更容易学习和表示各种特征
- 隐藏层增加意味着由激活函数带来的非线性变换的嵌套层数更多, 能构造更加复杂的映射
网络操作与计算
卷积神经网络中卷积操作和互相关操作的关系
- 实际上卷积神经网络中的卷积操作为互相关操作
- 严格卷积操作: 需要将卷积核上下左右翻转后再进行互相关操作
- 但图像处理中大部分的卷积核都是中心对称的, 互相关操作与卷积操作一致
池化层
- 种类:最大池化和平均池化
- 最大池化:前向传播时将最大值作为结果, 反向传播时通过最大值的位置传播梯度, 其他位置梯度为0
- 平均池化:前向传播时将平均值作为结果, 反向传播时将梯度均分给每个位置
- 选择与实际应用
- 最大池化:可以学到图像的边缘和纹理结构, 用于减小估计值的方差, 保留强激活值但容易过拟合
- 平均池化:减小估计值均值的偏移, 会弱化强激活值
- 池化层的作用
- 增加非线性
- 保留主要特征的同时减少参数(降维)和计算量, 防止过拟合, 提高模型泛化能力
- 利用
max pooling可以引入平移不变性, 旋转不变性和尺度不变性, 从而可以增大感受野 - 但在降维过程中会损失一部分信息
- 其他池化方法:
- 重叠池化: 相邻池化窗口之间重叠
SPP(空间金字塔池化): 用大小不同的池化窗口作用域feature mapCNN加入SPP层之后,CNN可以处理任意大小的输入, 模型更加灵活
卷积,池化尺寸及感受野计算
- 卷积:
- 池化:
- 感受野: ,
s和k是第N-2层的 - [ ] 代码实现卷积操作
激活函数
为什么需要非线性激活函数
- 为什么需要激活函数
- 激活函数对模型学习、理解非常复杂和非线性的函数具有非常重要的作用
- 激活函数可以引入非线性因素
- 激活函数可以把当前特征空间通过一定线性映射转换到另一个空间
- 为什么激活函数需要非线性函数
- 若网络全部为线性组件, 线性的组合还是线性, 与单独一个线性分类器无异. 不能用非线性来逼近任何函数
- 使用非线性激活函数, 网络会更加强大, 使用非线性激活函数, 能够从输入输出之间生成非线性映射
激活函数的性质
- 非线性: 非线性激活函数, 一个两层的神经网络基本就可以逼近所有函数
- 连续并可导(允许少数点上不可导)
- 单调性: 当激活函数单调时, 单层网络能保证是凸函数
- 激活函数及导函数要尽可能的简单, 有利于提高网络计算效率
- :当激活函数满足这个性质的时候, 如果参数的初始化是随机的较小值, 那么神经网络的训练将会很高效; 如果不满足这个性质, 那么就需要详细地去设置初始值;
- 激活函数的导函数的值域要在一个合适的区间内, 不能太大也不能太小, 否则会影响计算的效率和稳定性
激活函数详解
Sigmoid函数- 函数公式:
- 导函数:
- 软饱和性:当sigmoid函数的输入很大或很小时, 梯度会消失
- 导致sigmoid函数在隐藏层中使用较少, 使用更简单更容易训练的
ReLu函数替代
- 导致sigmoid函数在隐藏层中使用较少, 使用更简单更容易训练的
- 在二分类与多分类多标签问题中, 损失函数为
sigmoid+nn.BCELoss();多分类单标签问题损失函数nn.CrossEntropyLoss(), 无需手动做softmaxnn.BCEWithLogitsLoss()函数等效于sigmoid + nn.BCELoss
- 优点: 函数平滑容易求导
- 缺点:
- 容易造成梯度消失
- 存在幂运算, 计算量大
- 输出不关于零点对称
Tanh函数- 函数公式:
- 导函数:
- 可以看作放大并平移的
sigmoid函数 Tanh函数优缺点总结:- 具有
Sigmoid的所有优点 exp指数计算代价大, 梯度消失问题依然存在
- 具有
- 优点:
- 函数平滑, 容易求导
- 输出关于零点对称
- 缺点:
- 容易造成梯度消失
- 计算量大
ReLu函数- 公式:
ReLu函数仅保留正元素并丢弃所有负元素- 优点
ReLU激活函数计算简单, 且运算速度较快ReLu单侧抑制, 使一部分神经元输出为0, 使网络具有稀疏性, 且减少了参数的相互依存, 解决了过拟合的问题- 函数在
x > 0时导数为1的性质(左饱和函数), 在一定程度上缓解了神经网络的梯度消失问题, 加速梯度下降的收敛速度
- 缺点
- ReLU 神经元在训练时比较容易“死亡”(如果神经元参数值在一次不恰当的更新后, 其值小于 0, 那么这个神经元自身参数的梯度永远都会是 0, 在以后的训练过程中永远不能被激活, 这种现象被称作“死区”)
- ReLU 函数的输出是非零中心化的, 给后一层的神经网络引入偏置偏移, 会影响梯度下降的效率
Leaky ReLU函数- 为了缓解“死区”现象, 研究者将 ReLU 函数中 x < 0 的部分调整为 , 其中 常设置为 0.01 或 0.001 数量级的较小正数. 这种新型的激活函数被称作带泄露的 ReLU(
Leaky ReLU) - 公式:
- 为了缓解“死区”现象, 研究者将 ReLU 函数中 x < 0 的部分调整为 , 其中 常设置为 0.01 或 0.001 数量级的较小正数. 这种新型的激活函数被称作带泄露的 ReLU(
PReLU函数- 为了解决 Leaky ReLU 中超参数 不易设定的问题, 有研究者提出了参数化 ReLU(Parametric ReLU,
PReLU).参数化 ReLU 直接将 也作为一个网络中可学习的变量融入模型的整体训练过程 - 对于第 个神经元,
PReLU的定义为:
- 为了解决 Leaky ReLU 中超参数 不易设定的问题, 有研究者提出了参数化 ReLU(Parametric ReLU,
Swish函数- 公式:
- 其中 为 Logistic 函数, 为可学习的参数或一个固定超参数. 可以看作一种软性的门控机制
- 当 接近于
1时, 门处于“开”状态, 激活函数的输出近似于 本身 - 当 接近于
0时, 门的状态为“关”, 激活函数的输出近似于0
- Swish 函数可以看作线性函数和 ReLU 函数之间的非线性插值函数, 其程度由参数 控制
- 公式:
相对于sigmoid激活函数, tanh激活函数输出关于零点对称的好处
sigmoid函数其输出始终为正, 导致在深度网络训练中模型的收敛速度变慢, 因为在反向传播链式求导过程中, 权重更新的效率会降低sigmoid函数的输出均大于0, 作为下层神经元的输入会导致下层输入不是0均值的, 随着网络的加深可能会使得原始数据的分布发生改变. 而在深度学习的网络训练中, 经常需要将数据处理成零均值分布的情况, 以提高收敛效率, 因此tanh函数更加符合这个要求sigmoid函数的输出在[0,1]之间, 比较适合用于二分类问题
如何解决ReLu神经元死亡的问题
- 为什么ReLU会出现神经元死亡的问题
- 当学习率比较大, 而且梯度也很大时, 会导致权重更新太多, 有可能出现对于所有的训练样本, 该神经元输出都<0, 那么该神经元的权值就不会再更新了
- 解决方法
- 采用
Leaky ReLu等激活函数: 使其在该神经元的输出为负时, 仍然可以对该神经元进行梯度更新 - 设置较小的学习率进行训练: 尽可能避免因为梯度过大更新导致对于神经元的所有输入的输入都小于0
- 使用momentum优化算法动态调整学习率: 使用momentum优化算法, 利用惯性, 抑制异常数据的更新方向, 避免神经元死亡
- 采用
softmax定义及作用
softmax是logistic函数的一种泛化, 是网络预测多分类问题的最佳激活函数- 加入的幂函数可形成两极化, 正样本的结果趋近于1, 负样本的结果趋近于0
- 用于将分类结果归一化, 形成概率分布
- 由于指数函数的方法作用过于明显, 直接使用公式容易导致数据溢出
1 | import numpy as np |
Batch_Size
在合理的范围内, 增大Batch_Size的好处
- 增加内存利用率, 大矩阵乘法的并行化效率提高
- 对相同数据量的处理速度加快, 跑完一个
epoch(全数据集)需要的迭代次数减少 - 一定范围内,
Batch_Size越大, 其确定的下降方向越准, 引起的训练震荡越小
盲目增大Batch_Size的坏处
- 内存容量可能不够
- 跑完一次
epoch(全数据集)所需的迭代次数减少, 要想达到相同的精度, 其所花费的时间大大增加了, 从而对参数的修正也就显得更加缓慢 - Batch_Size 增大到一定程度, 其确定的下降方向已经基本不再变化
归一化
为什么要归一化
- 为了后面数据处理更加方便, 可以避免一些数值问题
- 为了程序运行时收敛加快
- 统一量纲
- 避免神经元饱和. 当神经元的激活在接近
0或1时会饱和, 梯度几乎为0, 造成无法更新 - 保证输出数据中数值小的不被吞食
为什么归一化能提高求解最优解速度

- 在使用梯度下降法寻求最优解时, 很有可能走“之字型”路线(垂直等高线走),从而导致需要迭代很多次才能收敛; 而右图对两个原始特征进行了归一化,其对应的等高线显得很圆,在梯度下降进行求解时能较快的收敛
为什么对数值型特征做归一化
- 消除特征之间量纲的影响, 使得不同特征之间具有可比性
- 在使用随机梯度下降求解时, 能加快模型收敛速度
- 归一化之后, 损失函数等高线图大致为圆形的, 更新方向与等高线垂直更加平滑, 而未归一化等高线图为椭圆形, 更新方向为横向
- 归一化可能提高精度, 一些分类器需要计算样本之间的距离, 小的特征值域范围更加有利于计算
为什么输入网络前对图像进行归一化
- 灰度数据表示一种是
uint8, 另一种是double. 当运算的类型为double是需要进行归一化 - 在使用随机梯度下降求解时, 未进行归一化输入分布差异很大, 各个参数的梯度数量级不同, 需要的学习速度不同, 归一化后可以方便的选择学习率
- 标准化后实现了数据中心化, 数据中心化符合数据分布规律, 能增加模型泛化能力
BN层的深入理解
BN介绍- 不同层的数据分布会往激活函数的上限或下限偏移, 第一层数据分布改变会导致第二层分布改变, 模型拟合效果会降低, 收敛速度下降(对下一轮更新时数据陌生), BN将每一层数据标准化到高斯分布
- 核心公式
BN对数据进行了变换重构, 引入可学习参数使网络可以恢复出原始网络所要学习的特征分布, 可以避免使用强制归一化, 大多数的数据无法激活, 学习特征被破坏
BN中的均值与方差通过哪些维度计算得到- 神经网络中的张量数据维度为
[N, C, H, W],BN在NHW维度做均值, 从而得到2C个训练参数(将每个通道的数据单独相加, 再除以N*H*W) - 训练时: 均值和方差分别是该批次内数据相应维度的均值与方差
- 推理时: 均值为所有训练时
batch的\mu_B的平均值, 方差为训练时每个batch的的无偏估计
- 神经网络中的张量数据维度为
BN的优缺点- 优点
- 防止网络梯度消失
- 加速训练, 且允许更大的学习率: 通过
normalization数据分布在合适的范围, 经过激活函数可以得到不错的梯度, 训练更快 - 降低参数初始化敏感度: 随着网络层数的增加, 分布逐渐发生偏移, 之所以收敛慢, 是因为整体分布往非线性函数取值区间的上下限靠近. 这会导致反向传播时梯度消失. BN就是通过规范化的手段, 把每层神经网络任意神经元这个输入值的分布强行拉回到均值0方差1的标准正态分布, 使得激活函数输入值落入非线性函数中比较敏感的区域
- 提高网络泛化能力防止过拟合: 因为
BN统计了一个batch内所有样本的信息, 从而引入了一定的噪声, 这个噪声也就起到了正则化的作用 - 可以把训练数据彻底打乱
- 缺点:
- 如果
Batch Size太小, 则BN效果明显下降 - 对于有些像素级图片生成任务来说,
BN效果不佳 RNN等动态网络使用BN效果不佳, 且使用起来不方便
- 如果
- 优点
- 其他的几种类似
BN结构LN: 在N通道归一化IN: 在CN通道归一化GN: 部分特征图在同一batch归一化
- [ ] BN的代码实现
预训练与微调
什么是模型微调fine tuning
- 别人的参数、修改后的网络和自己的数据进行训练,使得参数适应自己的数据,这样一个过程,通常称之为微调
微调先冻结底层,训练顶层的原因?
首先冻结除了顶部改动层以外的所有层参数,对顶层进行训练,这个过程可以理解为顶层的域适应训练,主要用来训练适应模型的现有特征空间,防止顶层糟糕的初始化,对已经具备一定表达能力的层的干扰和破坏,影响最终的性能。之后,在很多深度学习框架教程中会使用放开顶层往下一半的层数,继续进行微调。这样的好处在于越底层的特征通常是越通用的特征,越往上其整体的高层次语义越完备,这通过感受野很容易理解。所以,若预训练模型的数据和微调训练的数据语义差异越大(例如ImageNet的预模型用于医学图像的训练),那越往顶层的特征语义差异就越大,因此通常也需要进行相应的调整
权重偏差初始化
为什么神经网络权重不能初始化为0
因为所有参数为0, 经过第一层网络后, 所有的输入为0, 因此从第二层网络开始, 所有的输入神经元均一样, 从而打破了"非对称性"原则.
因此每次反向传播每个神经元得到的更新都是相同的, 网络无法正常学习
- 结论
- 网络中不可以连续相邻两层及以上的权重全部置
0, 否则会出现权值对称性问题
- 网络中不可以连续相邻两层及以上的权重全部置
为什么神经网络权重不能设为相同的值
权重设为非0相同值, 本质上也是使第二层网络开始形成了近似的对称性, 从而使网络梯度更新的非常慢
为什神经网络的最后一层可以将所有权值初始化为0
- 因为最后一层网络的输入不相同(即), 所以最后一层的权值依然可以正常更新. (最后一层的偏置, 永远都可以正常更新, 无论是否全部初始化为0)
- 而其他层正常初始化, 依然可以正常更新, 所以整个网络都可以正常更新.
- 使用场景:
- 如注意力机制中, 一般只是为了学习特征的增量用于shortcut, 理论上这个增量不能太大, 因此, 将注意力模块的最后一层卷积设置为0, 使其在最优值附近, 方便收敛,
逻辑回归参数初始化为什么可以设置为0
如果都初始化为0时, 由于输入不一样, 所以最后他们的变化率都不为0, 且都不相同, 所以权值可以正常更新
参数初始化方法
- 过大或过小的初始化:如果权值的初始值过大,则会导致梯度爆炸,使得网络不收敛; 过小的权值初始值,则会导致梯度消失,会导致网络收敛缓慢或者收敛到局部极小值
- 权值的初始值过大,则
loss function相对于权值参数的梯度值很大,每次利用梯度下降更新参数的时,参数更新的幅度也会很大,导致loss function的值在其最小值附近震荡
+ 过小的初值则相反,loss关于权值参数的梯度很小,每次更新参数时,更新的幅度也很小,导致loss的收敛很缓慢,或者在收敛到最小值前在某个局部的极小值收敛了
- 权值的初始值过大,则
- 方法选择:
- 优先采用
Pre-train初始化, 随机初始化带BN,He初始化
- 优先采用
- 随机初始化带
BN方法BN可以将过大或过小的数据都归一化到0-1分布, 避免了梯度爆炸或梯度消失
Xavier初始化- 基本思想: 保证输入和输出的数据分布(均值和方差)一致, 使网络具有更好的信息流动, 更易学习
Xavier初始化主要用于tanh, 不适用于ReLu, 适合关于0点对称的激活函数- 根据输入和输出神经元的数量自动决定初始化的范围:定义参数所在的层的输入维度为 , 输出维度为, 那么参数将从均匀分布中采样
- 为什么方差相等, 就可以使得网络有更好的信息流动
- 在考虑线性激活函数的情况下, 在初始化的时候使各层神经元的方差保持不变, 即使各层有着相同的分布.
- 如果每层都用N(0, 0.01)随机初始化的话, 各层的数据分布不一致, 随着层度的增加, 神经元将集中在很大的值或很小的值, 不利于传递信息.
- 很多初始化策略都是为了保持每层的分布不变, 而BN是通过增加归一化层使得每层数据分布保持在N(0, 1)
He初始化Xavier初始化适合关于0点对称的激活函数, 不适合Relu- He初始化非常适合ReLu激活函数;
- 主要解决的问题: 由于经过
ReLu后, 方差会发生变化, 因此初始化权值的方法也应该变化. 只考虑输入个数时, MSRA初始化是一个均值为0, 方差为2/n的高斯分布: He初始化的思想是: 在ReLU网络中, 假定每一层有一半的神经元被激活, 另一半为0, 要保持方差不变, 只需要在Xavier的基础上再除以2:
1 | w = np.random.randn(node_in, node_out) / np.sqrt(node_in/2) |
1 | # 常见的初始化权重写法 |
- 参数
xavier_normal_初始化:针对激活函数为sigmoid的kaiming_normal_初始化:针对激活函数为relu的constant_:初始化为常数
学习率
学习率的作用
- 梯度下降通过多次迭代, 并在每一步中最小化成本函数, 在迭代中学习率会控制模型得学习进度
- 在迭代得前提, 学习率大便于以较快得速度进行梯度下降, 而在后期, 逐渐减小学习率有助于算法收敛, 更容易得到最优解
学习率衰减方法
- 分段常数衰减
- 指数衰减
- 自然指数衰减
- 多项式衰减
- 余弦衰减
数据增强方式
- 随机缩放
- 随机裁剪: 对图片随机
0.6-1比率大小进行裁剪- 可以保留主要特征, 而裁剪掉背景噪声, 避免噪声的过拟合
- 随机反转
- 随机旋转
- 色彩扰动: 亮度, 对比度, 饱和度, 色调, 高斯噪声
- 随机擦除(Random Erasing): 随机选择一个区域利用随机值覆盖, 模拟遮挡场景
- 把物体遮挡一部分后依然能够分类正确, 那么肯定会迫使网络利用局部未遮挡的数据进行识别, 加大了训练难度, 一定程度会提高泛化能力
- cutout: 与Random Erasing类似
- 只有正方形: 大小与形状更重要
- 填充值只有零或其他纯色填充
- mixup: 增加了样本数量, 丰富了目标背景, 提高模型的泛化能力
- cutMix:
CutOut和MixUp的结合 - mosaic:
- 丰富数据集:随机使用4张图片, 随机缩放, 再随机分布进行拼接, 大大丰富了检测数据集, 特别是随机缩放增加了很多小目标, 让网络的鲁棒性更好
- 减少GPU小号: Mosaic增强训练时, 可以直接计算4张图片的数据, 使得Mini-batch大小并不需要很大, 一个GPU就可以达到比较好的效果
- copypaste: 将实例分割的目标, 随机贴在不同的图片上, 以增加数据的多样性
Label-smooth详解
- 通常情况下标签都是
one-hot编码(极端约束), 为了缓和label对网络的约束, 提高模型泛化能力, 减少过拟合风险- 采用软标签, 可以缓和标注错误的样本带来的大损失, 抑制噪声样本, 防止产生较大的损失(不希望模型对预测结果过度自信)
- 公式: , 为自定义参数
- 交叉熵损失发生变化
- 最优的预测概率分布发生变化:
- 为任意实数, 最终通过抑制正负样本输出差值, 使得网络有更好的泛化能力
卷积神经网络
卷积神经网络的特点
- 局部连接: 使用感受野进行连接
- 权值共享: 计算同一深度的神经元时采用的卷积核参数是共享的
- 池化操作: 池化操作与多层次结构一起,实现了数据的降维,将低层次的局部特征组合成为较高层次的特征,从而对整个图片进行表示
卷积层和池化层的区别
| 卷积层 | 池化层 | |
|---|---|---|
| 结构 | 零填充时输出维度不变,而通道数改变 | 通常特征维度会降低,通道数不变 |
| 稳定性 | 输入特征发生细微改变时,输出结果会改变 | 感受域内的细微变化不影响输出结果 |
| 作用 | 感受域内提取局部关联特征 | 感受域内提取泛化特征,降低维度 |
| 参数量 | 与卷积核尺寸、卷积核个数相关 | 不引入额外参数 |
CNN分类网络的演变脉络及各自的贡献与特点
LeNet-5- 贡献与关键点:
- 第一个将反向传播应用于实际的CNN架构
- 定义了基础组件: 卷积, 池化, 全连接;(称为
CPF三件套)
- 贡献与关键点:
AlexNet- 贡献与关键点:
- 多
GPU训练技术 - 使用了
ReLu激活函数, 使之有较好的梯度特性, 训练更快 - 使用了随机失活(Dropout技术)
- 大量使用数据扩充技术
- 多
- 贡献与关键点:
VGG- 贡献与关键点:
- 结构简单, 只有
3×3卷积和2×2汇合两种配置, 并且重复堆叠相同的模块组合. 卷积层不改变空间大小, 每经过一次汇合层, 空间大小减半;3x3卷积层的堆叠可以在获得相同感受野的前提下使用更少的参数, 多层的卷积也能增加模型的非线性效果 - 初始化方法: 先训练浅层网络, 并使用浅层网络对深层网络进行初始化
- 结构简单, 只有
- 贡献与关键点:
GoogLeNet- 提出了
Inception模块, 同时用1×1、3×3、5×5卷积和3×3汇合, 并保留所有结果 - 贡献与关键点:
- 多分支分别处理, 并级联结果
- 为了降低计算量, 使用
1*1卷积降维 - 使用了全局平均汇合替代全连接层, 使网络参数大幅减少
- 提出了
ResNet- 贡献与关键点:
- 使用短路连接, 使训练深层网络更容易, 并且重复堆叠相同的模块组
- 短路连接可以有效缓解反向传播时由于深度过深导致的梯度消失现象, 这使得网络加深之后性能不会变差
- ResNet就引入短路连接
shortcut connect机制, 直接将恒等映射做为网络的一部分, 将问题转换为学习一个残差函数. 拟合残差要比拟合恒等映射要容易的多
- ResNet大量使用了批量归一层
- 对于很深的网络(超过50层), ResNet使用了更高效的**瓶颈(Bottleneck)**结构
- 使用短路连接, 使训练深层网络更容易, 并且重复堆叠相同的模块组
- 贡献与关键点:
ResNeXt- 贡献与关键点:
- 在
ResNet的短路连接基础上, 综合了Inception的优点, 使用多分支进行处理, 但是与Inception不同的是, 其每个分支的结构都相同 ResNeXt巧妙地利用分组卷积进行实现
- 在
- 贡献与关键点:
DenseNetDenseNet其目的也是避免梯度消失- 和
residual模块不同,dense模块中任意两层之间均有短路连接 - 语义融合的代表, 通过跳跃连接所有的层来获得更好的聚合特征和误差

神经网络模型复杂度分析
- 模型计算量分析
- FLOPs: 浮点运算次数(计算量), 可以用来衡量算法/模型时间的复杂度
- FLOPS: 每秒执行的浮点运算次数(计算速度), 衡量硬件性能/模型速度的指标
- MACCs: 乘加操作次数(一个乘法累加算作一个MAC)
- 卷积层计算:
- 全连接层计算: 是输入层的维度, 是输出层的维度
- 模型参数量分析:
- 卷积层权重参数量
- BN 层参数量
- 全连接层参数量
nvidia-smi中GPU利用率的含义
- 该利用率表示的是在采样时间段内一个或多个内核在GPU上执行的时间百分比(内核运行时间占总时间的比例)
- 并不能体现算力的发挥情况
- 误区1:
GPU利用率=GPU内计算单元干活的比例 - 误区2: 同等条件下利用率越高, 耗时一定越短
延迟Latency和吞吐量Throughput的介绍
- 延迟
Latency:指提出请求与收到反应之间经过的时间 - 吞吐量
Throughput:一个时间单元内网络能处理的最大输入样例数
2 目标检测基础知识
anchor box介绍
- 不同模型使用的区域采样算法可能不同
- 两阶段检测模型常用的一种方法是: 以每个像素为中心生成多个大小和宽高比不同的边界框, 这些边界框称为锚框(
anchor box) Faster RCNN中, 每个像素都生成9个大小和宽高比不同的anchors, 长宽比为{1:1, 1:2, 2:1}, 由此引入检测中常用的多尺度方法
IOU的介绍及其变形介绍
-
IOU为交并比, 是模型产生的候选框与原标记框的交叠率, ==不仅用来确定正样本和负样本, 还可以用来评价输出框与ground-truth的距离- 公式:
- 作为损失函数出现的问题(缺点)
- 当两个框没有相交时,
IoU=0, 不能反映两者的距离大小, 没有梯度回传, 无法进行学习任务 IoU无法精确的反应两者的重合大小
- 当两个框没有相交时,
-
GIoU: 先计算两个框最小的闭包面积(预测框和真实框的最小外接矩形), 再计算闭包区域中不属于两个框的区域在闭包中的比重, 最后用IoU减比重即得GIoU- 原因:由于IoU是比值的概念, 对目标物体的scale是不敏感的. 然而检测任务中的BBox的回归损失(MSE loss, l1-smooth loss等)优化和IoU优化不是完全等价的, 而且 Ln 范数对物体的scale也比较敏感, IoU无法直接优化没有重叠的部分
- 公式: , 为最小闭包的面积
- 特性:
- 与
IOU相似, 为距离度量, 作为损失函数 GIOU对scale不敏感GIOU不仅关注重叠区域还关注非重合区域
- 与
-
DIOU(Distance-IOU): 更符合目标框回归的机制, 将目标与anchor之间的距离, 重叠率以及尺寸都考虑进去, 使得回归变得更加稳定, 不会出现发散等问题- 公式: , 为预测框与目标框中心点的距离, 为最小外接矩形的对角线距离
- 特性:
- 作为损失函数, 在与目标框不重叠时, 仍然可以为边界框提供移动方向
- 可以直接最小化两个目标框的距离,收敛更快
- 相当于在保留GIoU损失优点的基础上, 增加了中心点距离度量, 直接优化两个框中心距离, 快速收敛, 而且仅中心点完全重合的时候, 才会退化成IoU
- 可以替代普通的 IoU 评估, 应用于NMS中, 效果更合理
-
CIOU(complete-IOU): 在DIOU的基础上考虑长宽比- 公式:, 为权重系数, 用来衡量长宽比的相似性
- 从参数的定义可以看出, 损失函数会更加倾向于往重叠区域增多方向优化, 尤其是IoU为零的时候. 只要当IOU足够大的时候才开始着重优化宽高比, 否则优先优化IOU和距离
-
[ ] 三者的代码实现
Cross Entropy交叉熵损失函数介绍
- 常使用交叉熵来作为分类任务中训练数据分布和模型预测结果分布间的代价函数
- 交叉熵定义:, P为真实分布, Q为预测分布
- 二分类问题中交叉熵一般形式(CE):, 其中 表示当预测样本等于 的概率, 则 表示样本等于 的预测概率
- 对于所有样本, 二分类交叉熵为 , 其中 为正样本个数, 为负样本个数, 为样本总数,
- 当样本类别不平衡时, 损失函数 的分布也会发生倾斜, 造成模型对少样本类别的性能较差
- 对于所有样本, 多分类的交叉熵损失为: , 其中 表示类别数量, 是符号函数, 如果样本 的真实类别等于 取值 1, 否则取值 0; 表示样本 预测为类别 的概率
- 多分类的
loss不用考虑负样本, 只考虑正样本的判断准确率提高即可
Balanced Cross Entropy损失函数介绍
- 对于正负样本不平衡的问题, 引入 参数:
- 对于所有样本, 二分类的平衡交叉熵损失函数:, 其中 , 即 参数的值是根据正负样本分布比例来决定的
- 为什么取
0.25- 是为了平衡正负样本的数量, 一般样本越多的类, 越低
- 目标检测中, 在正样本前, 用于平衡正负样本
loss比例, 单独使用时一般大于0.5, 论文中设置为0.75效果最好, 会增加正样本对损失的贡献 - 在
Focal Loss中, , 使用focal loss之后, 很多易分负样本权重被降的很低, 继而导致难分正样本比难分负样本数量多, 所以小于0.5
Focal Loss损失函数介绍
Balanced Cross Entropy中 参数平衡了正负样本(positive/negative), 但是不能区分难易样本(easy/hard)- 目标检测中大量的候选目标都是易分样本, 这些样本的损失很低,但是主导了总的损失; 易分样本(置信度高的样本)对模型的提升效果非常小, 模型应该主要关注那些难分样本
Focal Loss在交叉熵损失函数上加上一个调整因子(modulating factor), 把高置信度 (易分样本)样本的损失降低- 定义:
Focal Loss有两个性质:- 当样本被错误分类且 值较小时,调制因子接近于
1,loss几乎不受影响;当 接近于1, 调质因子(factor)也接近于0, 容易分类样本的损失被减少了权重, 整体而言, 相当于增加了分类不准确样本在损失函数中的权重 - 参数平滑地调整容易样本的权重下降率, 当 时,
Focal Loss等同于CE Loss. 在增加, 调制因子的作用也就增加, 实验证明 时, 模型效果最好
- 当样本被错误分类且 值较小时,调制因子接近于
- 调制因子减少了简单样本的损失贡献, 并扩大了样本获得低损失的范围
- 在实践中常采用带 的
Focal Loss: - 实验表明 取 2, 取 0.25 的时候效果最佳
- 在实践中常采用带 的
- 的作用
- 用于决定对易分样本的衰减程度, 越大代表对易分样本的衰减程度越高, 即网络更加关注难分样本
- 当时, 就变成了带有正负样本平衡的普通CE loss
smooth L1 loss介绍
L2 Loss为均方误差(MSE)- 优点
- 相比于L2损失函数, 其对离群点(指的是距离中心较远的点), 异常值(outlier)不敏感, 当异常值出现时, 不至于产生特别大的梯度, 造成梯度爆炸
- 相比于L1损失函数, 解是稳定的, 对于L1, 数据的一个微小移动就很可能导致参数跳过最优解, 无法收敛到最优. 梯度不至于过大, 且梯度可以足够小
NMS算法介绍
- 目标检测中, 常使用非极大值抑制算法对生成的大量候选框进行后处理,去除冗余的候选框, 得到最佳检测框
NMS的本质思想:搜索局部最大值, 抑制非极大值NMS的目的就是除掉重复的边界框, 通过迭代的形式, 不断地以最大得分的框去与其他框做IoU操作, 并过滤那些IoU较大的框- 实现的思想主要是将各个框的置信度进行排序, 然后选择其中置信度最高的框
A, 同时设置一个阈值, 当其他框如B框 与A框的重合程度超过阈值就将B舍弃掉, 然后在剩余的框中选择置信度最大的框, 重复上述操作
bounding box voting介绍
- 思想: 根据
NMS被抑制掉重合度较高的Box修正NMS之后的边界框(参与投票的只有NMS滤除的框) - 流程
NMS处理后得到NMS框- 利用该框与其他预测的
NMS框取交集分别计算IOU, 取大于阈值的框作为后选框 - 后选框中利用加权均值的方法得到最终的框, 权重为每个框的置信度
- 再根据评分进行过滤
Soft NMS算法介绍
NMS算法存在一个问题是可能会把一些相邻检测框框给过滤掉(即将IOU大于阈值的窗口的得分全部置为0), 从而导致目标的recall指标比较低Soft NMS算法会为相邻检测框设置一个衰减函数而非彻底将其分数置为零- 思想: 为当前得分最高框, 为待处理框, 和 的 IOU 越大, bbox 的得分 就下降的越厉害 ( 为给定阈值)
- Soft NMS 在每轮迭代时, 先选择分数最高的预测框作为 , 并对 中的每一个检测框 进行 re-score, 得到新的 score, 当该框的新 score 低于某设定阈值时, 则立即将该框删除
- 线性加权:
- 高斯加权:
TP, TN, FP, FN的含义
| 名称 | 定义 |
|---|---|
True Positive(真正例, TP) |
将正类预测为正类数 |
True Negative(真负例, TN) |
将负类预测为负类数 |
False Positive(假正例, FP) |
将负类预测为正类数 → 误报 (Type I error) |
False Negative(假负例子, FN) |
将正类预测为负类数 → 漏报 (Type II error) |
- TP的定义:
- 预测框与真实框的
IOU大于阈值(为0.5) - 置信度评分高于设定的置信度阈值(通过改变置信度阈值得到不同的PR指, 从而得到PR曲线)
- 预测框与真实框的
- 当对应一个真值有多个预测结果时, 置信度最高的结果为
TP, 其余为FP
精确率、召回率与F1
- 准确率(精度)
Accuracy:- 准确率可以判断总的正确率, 但是再样本不平衡的情况下不能很好的作为指标来衡量结果
- 精确率(查准率)
P:- 精确率代表对正样本结果中的预测准确程度, 而准确率代表整体的预测准确程度
- 精确率描述了模型有多准
- 召回率(查全率)
R:- 召回率描述了模型有多全
F1分数P与R两者之间的平衡点:- 在 个二分类混淆矩阵上综合考虑查准率和查全率:
- 一种直接的做法是先在各混淆矩阵上分别计算出查准率和查全率, 记为 然后取平均, 这样得到的是"宏查准率(
Macro-P)“, “宏查准率(Macro-R)”, 及对应的"宏(Macro-F1)”:
- 一种直接的做法是先在各混淆矩阵上分别计算出查准率和查全率, 记为 然后取平均, 这样得到的是"宏查准率(
PR曲线
PR曲线是以Recall为横轴,Precision为纵轴, 展示的是Precision vs Recall曲线- P-R曲线越靠近右上角性能越好
PR曲线的两个指标都聚焦于正例PR曲线下的面积定义为APPR曲线为不同阈值条件下,Recall与Precision的对应关系
AP与mAP的理解
AP衡量的是训练好的模型在每个类别上的好坏mAP衡量的是模型在所有类别上的好坏- 取所有
AP的平均值即为mAP
- 取所有
mAP常作为目标检测算法的评价指标- 对于每张图片检测模型会输出多个预测框,使用
IoU来标记预测框是否预测准确 - 标记完成后, 随着预测框的增多, 查全率
R总会上升, 在不同查全率R水平下对准确率P做平均, 即得到 AP, 最后再对所有类别按其所占比例做平均, 即得到mAP指标
- 对于每张图片检测模型会输出多个预测框,使用
- 通常情况下通过插值计算
AP: 使用11点插值计算方法 - coco数据集中
mAP的计算- 设定多个
IOU阈值(0.5-0.95,0.05为步长), 在每一个IOU阈值下都有某一类别的AP值, 然后求不同IOU阈值下的AP平均, 就是所求的最终的某类别的AP值
- 设定多个
- [ ] 代码实现mAP计算
目标检测中的不平衡问题介绍
Class imbalance: 类别不平衡. 不同类别的输入边界框的数量不同, 包括前景/背景和前景/前景类别的不平衡RPN和Focal Loss就是解决这类问题
Scale imbalance: 尺度不平衡, 主要是目标边界框的尺度不平衡引起的, 也包括将物体分配至feature pyramid时的不平衡- 典型如
FPN就是解决物体多尺度问题的
- 典型如
Spatial imbalance: 空间不平衡. 包括不同样本对回归损失贡献的不平衡,IoU分布的不平衡, 和目标分布位置的不平衡Objective imbalance:不同任务(分类、回归)对总损失贡献的不平衡
ROI Pooling和ROI Align介绍
- 介绍:
- 在区域建议网络 RPN 得到候选框 ROI 之后, 需要提取该 ROI 中的固定数目的特征(
Faster R-CNN中的7*7)输入到后面的分类网络以及边界回归网络的全连接层中 Faster R-CNN中使用的方法是ROI Pooling- 对于像素位置精细度要求更高的
Mask R-CNN使用的方法是ROI Align
- 在区域建议网络 RPN 得到候选框 ROI 之后, 需要提取该 ROI 中的固定数目的特征(
- 区别:
ROI Pooling使用了两次量化操作ROI Align没有采用量化操作, 采用双线性插值方法
ROI PoolingFaster R-CNN中具有两次量化操作- 图像坐标 ->
feature map坐标 feature map坐标 ->ROI feature坐标
- 图像坐标 ->
- 两次量化操作影响检测算法的性能
- 将
RPN的浮点Bbox输出量化成整形; 然后从feature map中裁剪出对应的ROI, 并池化到指定大小
ROI Align- 直接使用
RPN的浮点Bbox, 将ROI等比例划分成多个cell, 且cell的数目与最终要求的池化输出大小一致; 从cell中随机采样一点数目的点(使用双线性差值计算浮点位置的特征), 并进行池化得到该cell的输出
- 直接使用

Anchor-free和Anchor-based区别
Anchor-based- 优点
- 使用
Anchor机制产生密集的Anchor box, 使得网络可直接在此基础上进行目标分类及边界框坐标回归. 加入了先验框, 训练稳定 - 密集的
Anchor box可有效提高网络目标召回能力, 对于小目标检测来说提升非常明显
- 使用
- 缺点
Anchor机制中, 需要设定的超参:尺度和长宽比是比较难设计的, 这需要较强的先验知识. 使得这些Anchor集合存在数据相关性, 泛化性能较差- 冗余框非常之多: 一张图像内的目标毕竟是有限的, 基于每个
Anchor设定大量Anchor box会产生大量的easy-sample, 即完全不包含目标的背景框. 这会造成正负样本严重不平衡问题, 也是one-stage算法难以赶超two-stage算法的原因之一. 使用包括two-stage的RPN和one-stage的Focal loss - 网络实质上是看不见
Anchor box的, 在Anchor box的基础上进行边界回归更像是一种在范围比较小时候的强行记忆 - 基于
Anchor box进行目标类别分类时,IOU阈值超参设置也是一个问题
- 优点
Anchor-free- 优点
Anchor-free要比Anchor-based少2/3的参数量, 因为Anchor-based一个位置要预测3个长宽不同的bbox, 而free只预测一个- 不需要像
Anchor一样, 不需要设置超参数 - 容易部署(这是
Anchor-free得以推广的主要原因)- 主要是解码方便: 直接对
heatmap使用池化, 就相当于做了NMS, 然后利用偏移和宽高就可以获得对应的检测框 FCOS使用了NMS, 而centernet是直接对点进行池化做NMSAnchor-based需要解码每个位置, 再使用NMS, 还需要实现求解出每个Anchor的位置和大小, 使得解码很麻烦
- 主要是解码方便: 直接对
- 缺点
- 正负样本极端不平衡
- 语义模糊性(两个目标中心点重叠), 现在这两者大多是采用
Focus Loss和FPN来缓解的, 但并没有真正解决 - 检测结果不稳定, 需要设计更多的方法来进行
re-weight
- 优点
- [ ] 原理介绍
3 深度学习问题总结
过拟合与欠拟合的变表现与解决办法
- 过拟合: 模型在训练集上表现好, 但在测试集(验证集)上表现差, 损失函数呈现高方差,低偏差的状态(高方差指训练集误差较低)
- 原因:
- 模型过于复杂, 导致将噪声的特征也学习到模型中, 使模型泛化性能下降
- 数据集规模较小, 使模型过度挖掘数据集中特征
- 解决办法:
- 获取更多的训练数据(数据扩充), 或使用迁移学习技术
- 降低模型复杂度(减层数减参数量)
- 正则化(L2正则化, 添加BN层, Dropout技术)
- Early Stop技术
- 交叉验证
- 集成学习
- 原因:
- 欠拟合: 模型在训练集和测试集上的表现都很差, 损失曲线呈现一种高偏差, 低方差状态;(高偏差指的是训练集和验证集的误差都较高, 但相差很少)
- 原因:
- 模型过于简单, 学习能力差
- 提取的特征不好, 特征不足或现有特征与标签的相关性不强
- 解决办法:
- 提高模型复杂度
- 增加新特征
- 若使用了正则项, 考虑减小正则项的系数
- 原因:
梯度消失和梯度爆炸以及解决方法
- 梯度消失和梯度爆炸都是出现在靠近输入层的参数中
- 产生原因:
- 梯度更新基于反向传播过程, 使用链式求导法则, 网络越深连乘的项越多就容易导致梯度值特别大或者接近零
- 梯度爆炸的原因:权值初始化太大
- 在使用
sigmoid激活函数时较少出现, 不容易发生 - 现象: 训练不稳定, loss突然变大或变小; 极端情况下, 权重值很大甚至溢出, 造成损失为
NaN
- 在使用
- 梯度消失的原因:使用了不合适的激活函数
- 解决办法:
- 梯度爆炸:
pre-training+fine-tunning- 梯度剪枝: 对梯度设定阈值
- 权值正则化: 正则化项限制权值大小(
L1,L2) - 改用其他激活函数(
ReLu) - BN: 对每一层的输出进行规范, 消除权重参数方法或缩小带来的影响, 将输出从饱和区拉到非饱和区
- 梯度消失:
- 改用其他激活函数(
ReLu) - BN
- 使用
ResNet的短路连接结构
- 改用其他激活函数(
- 梯度爆炸:
学习率和BatchSize对模型的影响
- 随机梯度下降算法的原理:
- 时批量大小,为学习率, 两个因子决定了权重的更新
- 学习率直接影响模型的收敛,
BatchSize影响模型的泛化能力
- 学习率
- 初始学习率过大模型不收敛, 过小导致模型收敛太慢或无法学习(可采用搜索法进行搜索)
- 学习率的值经验选择为:
0.1, 0.015, 0.01, 0.005, 0.001 - 不同的学习策略:
Mutistep: 每经过几个epoch调整一次学习率- 学习率衰减:
StepLR, MultiStepLR, ExponentialLR, CosineAnnealingLR, LambdaLR cyclical learning rate:周期性学习率warmup策略: 刚开始使用较小的学习率, 然后增大到设定的学习率, 最后又随着训练的进行慢慢减小学习率- 作用: 1. 有助于减缓模型在初始阶段对
mini-batch的提前过拟合现象, 保持分布的稳定; 2. 有助于保持模型深度的稳定性; - 由小到大: 初始时模型对数据分布理解为零, 较大的学习率导致模型不稳定, 容易过拟合; 随后适当增大学习率, 模型相对稳定, 收敛速度变快, 模型效果较好
- 由大到小: 学习率降低有助于较好的收敛
- 作用: 1. 有助于减缓模型在初始阶段对
Adam: 自适应学习率变换方法
BatchSize- 大的
BatchSize减少训练时间, 提高稳定性; 微调时,BatchSize更大效果更好 - 大的
BatchSize导致模型泛化能力下降
- 大的
- 如果增加了学习率, 那么batch size最好也跟着增加, 这样收敛更稳定
- BatchSize很大后(超过临界点)会降低模型的泛化能力, 在临界点下模型性能变化对学习率更敏感
10K样本用SGD,BatchSize在1, 100, 10000中取100收敛最快- 大的
BatchSize训练速度更快 BatchSize过大会导致模型泛化性能下降, 小BatchSize会更容易跳出局部最优点
- 大的
特征融合concat和add的区别
add- 对对应通道对应位置的值相加, 通道数不变
- 描述图像的特征个数不变, 但是每个特征下的信息增加
- 默认两个特征图对应通道所要表达的信息类似, 尺寸不一致时, 直接相加尺寸小的会被尺寸大的特征淹没, 不应该使用
add - 优点: 计算量少
- 缺点: 特征提取能力差
concat- 通道合并, 通道数变多
- 描述图像的特征个数变多, 但是每个特征的信息不变
- 直接通过训练学习来整合两个通道图通道之间的信息, 可以提取出合适的信息, 效果更好
- 优点: 特征提取能力强
- 缺点: 计算量大
为什么机器学习解决回归问题通常使用均方误差
- 如果采用的距离是两者之差的绝对值, 那么求解的目标函数:
- 如果采用的距离是两者之差的平方, 那么求解的目标函数:
- 其中: 即预测值, 为真实值, 为样本总数, 和 为要求解的参数
- 要求得使以上损失函数最小化对应的那个 和 , 可将损失函数对 和 求导, 并令导数为0
- 当采取的距离是两者之差的绝对值时, 函数在0处不可导, 且还增加的一个工作量是需要判断 正负号
- 而采用的距离是两者之差的平方时就没有这方面的问题
- 所以解决回归问题的时候一般使用平方损失
yolov5中正负样本的判断
- yolov5输出有3个预测分支, 每个分支的每个网格有3个anchor与之对应
- 没有采用IOU最大的匹配方法, 而是通过计算该
bounding box和当前层的anchor的宽高比; 如果最大比例大于4(设定阈值), 则比例过大, 则说明匹配度不高, 将该bbox过滤, 在当前层认为是背景. - 计算这些box落在哪个网格内, 同时利用四舍五入规则, 找出最近的两个网格, 将这三个网格都认为是负责预测该bbox的, 所以理论上最多一个gt会分配9个正样本anchor, 最少为3个(因为引入了相邻两个网格)
能够匹配的gt, 将其所处的grid, 及其临近的两个grid也分配为正样本
SGD和Adam的区别
- 优化函数如果训练比较小的自定义的数据集, adam是比较合适的选择, 但是如果训练大型的数据集那么使用sgd优化函数的比较多
- Adam引入了一阶动量:SGD容易陷入局部最优, 而一阶动量利用过去的信息, 可以帮助冲出局部最优点.
- Adam引入了二阶动量:实现了自适应学习率
- 对于经常更新的参数, 已经积累了大量关于它的知识, 不希望被单个样本影响太大, 希望学习速率慢一些
- 对于那些偶尔更新的参数, 了解的信息太少, 希望能从每个偶然出现的样本身上多学一些, 即学习速率大一些, 因此利用二阶信息就可以衡量每个参数的更新幅度
Adam缺点
- 可能不收敛
SGD没有用到二阶动量, 因此学习率是恒定的(实际使用过程中会采用学习率衰减策略, 因此学习率递减), 算法会使得学习率不断递减, 最终收敛到0, 模型也得以收敛Adam则不然. 二阶动量是固定时间窗口内的累积, 随着时间窗口的变化, 遇到的数据可能发生巨变, 使得可能会时大时小, 不是单调变化. 这就可能在训练后期引起学习率的震荡, 导致模型无法收敛
- 可能错过全局最优解
- 同样的一个优化问题, 不同的优化算法可能会找到不同的答案, 但自适应学习率的算法往往找到非常差的答案
- 自适应学习率算法可能会对前期出现的特征过拟合, 后期才出现的特征很难纠正前期的拟合效果
SGD的S(stochastic随机)体现在哪里
随机体现在, 每一步的梯度都是通过从全部数据中随机选择一个minbatch来计算loss得到的, minbatch的loss和全部数据loss不一样, 其是在不断的振动的, 但最后是达到全局最优的
模型搭建流程
- 模型搭建流程
- 加载数据.
train_loader = torch.utils.data.Dataloader() - 构建模型.
model = torch.nn.module - 构建损失.
loss = torch.nn.CrossEntropyLoss() - 构建优化器.
optimizer = torch.optim.Adam() - 设置学习率更新策略.
scheduler = torch.optim.lr_scheduler.MultiStepLR() - FP16, 设置FP16更新器.
scaler = torch.cuda.amp.GradScaler()
- 加载数据.
- 更新流程
- 读取数据.
for n_iter, (img, label) in enumerate(train_loader) - 前向传播.
output = model(img) - loss计算.
loss(output, label) - 反向传播, 计算梯度.
loss.backward() or scaler.scale(loss).backward() - 如果有FP16, 梯度还原.
scaler.unscale_(optimizer) - 使用优化器由梯度更新权重.
optimizer.step() or scaler.step(optimizer) - 整个epoch结束后, 更新学习率.
scheduler.step()
- 读取数据.
function和module的区别
Function一般只定义一个操作, 因为其无法保存参数, 因此适用于激活函数,pooling等操作;Module是保存了参数, 因此适合于定义一层, 如线性层, 卷积层, 也适用于定义一个网络Function需要定义三个方法:__init__,forward,backward(需要自己写求导公式);Module: 只需定义__init__和forward,backward的计算由自动求导机制构成- 可以不严谨的认为,
Module是由一系列Function组成, 因此其在forward的过程中,Function和Variable组成了计算图, 在backward时, 只需调用Function的backward就得到结果, 因此Module不需要再定义backward Module不仅包括了Function, 还包括了对应的参数, 以及其他函数与变量, 这是Function所不具备的
dataloader, dataset, sampler有什么区别
Dateloader中包含Sampler和Dataset, 使用sampler产生索引, 返回的也就是一批索引值, 然后通过索引去Dataset中找到对应的数据- Sampler产生索引, 返回的也就是一批索引值
- 在
enumerate(Dateloader对象)过程中,Dataloader按照其参数BatchSampler规定的策略调用其Dataset的getite,m方法batchsize次, 得到一个batch, 该batch中既包含样本, 也包含相应的标签
- 一般只需要定义
Dataset即可,shuffle=True(随机读取数据), batch_size=(一次读取的数据数), num_workers=(读取一个batch数据时所使用的进程数, 并行读取数据, 速度快) Dataset主要重写__getiterm__, 以便根据sample得到的索引来获取数据和标签
model.train和model.eval区别
- 主要是针对
BN和Dropout这种在训练和预测期间操作不同的结构- train阶段:BN和dropout在训练中起到防止过拟合的作用
- eval阶段:
- BN的参数直接固定, 不会再被改变, BN不会再计算输入数据的均值方差, 而是直接使用训练集统计出的均值方差, 这样就可以避免test的batchsize过小, 使得计算出的均值方差不具有统计特征, 使结果非常的差
- 使Dropout不起作用:训练时随机失活, 推理时全部开启, 同时最终输出要乘以失活比例, 否则会导致最后的结果翻倍
ModuleList和Sequential的区别
nn.Sequential里面的模块按照顺序进行排列的, 所以必须确保前一个模块的输出大小和下一个模块的输入大小是一致的- nn.Sequential内部实现了forward函数, 因此可以不用写forward函数. 而nn.ModuleList则没有实现内部forward函数
- nn.Sequential中可以使用OrderedDict来指定每个module的名字
- nn.Sequential里面的模块按照顺序进行排列的, 所以必须确保前一个模块的输出大小和下一个模块的输入大小是一致的; 而nn.ModuleList并没有定义一个网络, 它只是将不同的模块储存在一起, 这些模块之间并没有什么先后顺序可言, 执行顺序由forward函数决定
- 有的时候网络中有很多相似或者重复的层, 一般会考虑用 for 循环来创建它们(nn.ModuleList), 而不是一行一行地写(nn.Sequential)
nn.ModuleList- 不同于一般的 list, 加入到 nn.ModuleList 里面的 module 是会自动注册到整个网络上的, 同时 module 的 parameters 也会自动添加到整个网络中
- 若使用python的list, 则会出问题. 使用 Python 的 list 添加的卷积层和它们的 parameters 并没有自动注册到我们的网络中. 当然, 我们还是可以使用 forward 来计算输出结果. 但是如果用其实例化的网络进行训练的时候, 因为这些层的parameters不在整个网络之中, 所以其网络参数也不会被更新, 也就是无法训练
- 不同于一般的 list, 加入到 nn.ModuleList 里面的 module 是会自动注册到整个网络上的, 同时 module 的 parameters 也会自动添加到整个网络中
- 一般情况下 nn.Sequential 的用法是来组成卷积块 (block), 然后像拼积木一样把不同的 block 拼成整个网络, 让代码更简洁, 更加结构化. 而对于重复的层, 就使用nn.ModuleList及for来创建
设置随机种子, 使训练结果可复现
1 | def setup_seed(seed): |