写在前面
为什么不直接输出一堆内容,主要是因为自己太菜了,上学时的那些深度学习知识,已经差不多都还给老师了,而且工程应用又是另一码事。所以我就一边用mmyolo框架训模型,一边从头学起。。。
快成炼丹师了,不过对如何调整hyperparameters一点头绪都没。以下提到的功能的使用,都可以在mmyolo官方文档中找到说明。
mmyolo的安装
见mmlab的Github OpenMMLab (github.com)
因为是Python部署,直接新建一个conda环境即可,部署中遇到任何问题,可以直接Google。
AMP(Automatic mixed precision ) 自动混合精度训练
指的是在神经网络推理过程中,针对不同的层,采用不同的数据精度进行计算,从而实现节省显存和加快速度的目的。Pytorch的amp功能位于 torch.cuda.amp
模块下,不过只有拥有TensorCore的GPU才可以使用AMP。
自动:Tensor的dtype类型会自动变化,框架按需自动调整tensor的dtype,当然有些地方还需手动干预。
混合精度:采用不止一种精度的Tensor,torch.FloatTensor和torch.HalfTensor
大多数深度学习框架都采用32位浮点算法(FP32)进行训练。NVIDIA使用一种在训练网络时将单精度(FP32)与半精度(FP16)结合在一起的方法,并使用相同的超参数实现了与FP32几乎相同的精度。
FP16优势有三个:
- 减少显存占用
- 加快训练和推断的计算
- Tensor Core的普及,低精度计算是未来的趋势。
FP16也存在缺陷:
- 溢出错误,由于FP16的范围比FP32小的多,因此计算时容易出现上溢出&下溢出,也就是“NaN”问题。由于激活函数梯度比权重梯度小,更容易出现下溢出。
- 舍入误差,当梯度过小时,小于当前区间内的最小间隔时,该次梯度更新可能会失败。
因此在内存中用FP16做储存和乘法从而加速计算,而用FP32做累加从而避免上述问题。
冻结指定网络层权重
一些概念
先理解Backbone,Neck和Head的概念。
- Backbone:骨干网络,主要指用于特征提取的,已在大型数据集(例如ImageNet|COCO等)上完成预训练,拥有预训练参数的卷积神经网络,例如:ResNet-50、Darknet53,VGG-16,ResNeXt-101等。
- Neck:在Backbone和Head之间的网络层,是一系列混合和组合图像特征的网络层,将图像特征传递到预测层。一般分为Path-aggregation blocks 和 Additional blocks。
-
- Path-aggregation blocks: FPN(Feature Pyramid Network), PANet(Path Aggregation Network), NAS-FPN, Fully-connected FPN, BiFPN, ASFF, SFAM
-
- Additional blocks: SPP, ASPP, RFB, SAM
- Head:检测头,用于预测目标位置&类别,输出为Bounding Box(BBox)。可以分为Dense Prediction和Sparse Prediction。
-
- Dense Prediction:: RPN, YOLO, SSD(Single Shot MultiBox Detector), RetinaNet, FCOS。
-
- Sparse Prediction:Faster R-CNN, R-FCN, Mask R-CNN (anchor based)
- BottleNeck:网络输入的数据维度和输出的维度不同,输出的维度比输入的小了许多。
深度学习目标检测模型结构一般是:Input-> Backbone -> Neck-> Head-> Output。Backbone提取基本特征,Neck提取更复杂、深层的特征,Head继续预测和Output。
以YOLOv4为例,
Backbone:CSPDarknet53
Neck:SPP + PAN
Head:YOLOv3
冻结网络层
对于数据集本身很小(几千张图片)的情况,从头开始训练具有几千万参数的大型神经网络是不现实的,因为越大的模型对数据量的要求越大,过拟合无法避免。这时候如果还想用上大型神经网络的超强特征提取能力,只能靠微调已经训练好的模型。
对于图片来说,网络前几层学习到的是低级特征,比如,点、线、面,低级特征对于任何图片来说都是可以抽象出来的,所以我们将他作为通用数据,只微调这些低级特征组合起来的高级特征即可,例如,这些点、线、面,组成的是园还是椭圆,还是正方形,这些代表的含义是我们需要后面训练出来的。
对于语音来说,每个单词表达的意思都是一样的,只不过发音或者是单词的拼写不一样,比如 苹果,apple,apfel(德语),都表示的是同一个东西,只不过发音和单词不一样,但是他具体代表的含义是一样的,就是高级特征是相同的,所以我们只要微调低级特征就可以了。
在视觉领域,Fine-tuning 一般是固定前几层的参数,只对最后几层进行Fine-tuning,也就是抛开预训练模型,只训练自己定制的简配版全连接网络。
另一种方法是 Pre-trained models,是使用整个Pre-trained的model作为初始化,然后Fine-tuning整个网络而不是某些层,但是计算量很大,相当于只做了一个初始化(目前我是这样做的)。
被冻结的层可以正向&反向传播,但是这些层的参数不再更新,未冻结的正常更新。
随机种子
在同一开发环境中,随机数种子seed确定时,模型的训练结果将始终保持一致。
注意力机制
Context Block
Non-local Networks
Test-Time Augmentation(TTA,测试时数据增强)
数据增强是一种在模型训练期间使用的方法,它使用训练数据集中修改过的样本副本来扩展训练集。通常使用图像数据来执行数据增强,通过执行一些图像操作来创建训练数据集中的图像副本,例如缩放、翻转、移动等等。
mmyolo框架的应用
数据集
mmyolo框架支持多种格式的数据集,包括coco、voc等。目前我用的是voc格式的数据集,标注为xml格式。
使用 python tools/misc/download_dataset.py --dataset-name voc2012
命令可以下载voc2012数据集,注意,voc2012和voc2007是无交集的两个数据集。之后将数据集划分为训练集和测试集,我的数据集比较少,所以没有验证集。
配置文件的命名
接下来则是关于配置文件,比如 yolov8_x_syncbn_fast_8xb16-500e_psvoc.py
这个命名,是因为mmyolo官方那个遵循 {algorithm name}_{model component names [component1]_[component2]_[...]}-[version id]_[norm setting]_[data preprocessor type]_{training settings}_{training dataset information}_{testing dataset information}.py
这个风格来命名的。文件名分为 8 个部分,其中 4 个必填部分、4 个可选部分。 每个部分用 _ 连接,每个部分内的单词应该用 - 连接。{} 表示必填部分,[] 表示选填部分。
- {algorithm name}: 算法的名称。 它可以是检测器名称,例如 yolov5, yolov6, yolox 等。
- {component names}: 算法中使用的组件名称,如 backbone、neck 等。
- [version_id] (可选): 由于 YOLO 系列算法迭代速度远快于传统目标检测算法,因此采用 version id 来区分不同子版本之间的差异。
- [norm_setting] (可选): bn 表示 Batch Normalization, syncbn 表示 Synchronized Batch Normalization。
- [data preprocessor type] (可选): 数据预处理类型
- {training settings}: 训练设置的信息,例如 batch 大小、数据增强、损失、参数调度方式和训练最大轮次/迭代。
-
- {gpu x batch_per_gpu}: GPU 数和每个 GPU 的样本数。bN 表示每个 GPU 上的 batch 大小为 N。例如 4x4b 是 4 个 GPU 每个 GPU 4 张图的缩写。如果没有注明,默认为 8 卡每卡 2 张图。
-
- {schedule}:训练方案,MMYOLO 中默认为 300 个 epoch。
- {training dataset information}: 训练数据集,例如 coco, cityscapes, voc-0712, wider-face, balloon。
- [testing dataset information] (可选): 测试数据集,用于训练和测试在不同数据集上的模型配置。 如果没有注明,则表示训练和测试的数据集类型相同。
配置文件内容
MMYOLO 采用模块化设计,所有功能的模块都可以通过配置文件进行配置。
大部分配置文件的内容可以在 https://github.com/open-mmlab/mmyolo/blob/main/docs/zh_cn/tutorials/config.md 中找到,内有详细的注释。用的更多的是配置文件的继承。
配置文件继承
官方指南挂掉力,悲: https://mmengine.readthedocs.io/zh_CN/latest/tutorials/config.html
那我没地方复制粘贴力,根据自己的理解说一点。
在 config/_base_
文件夹中有 default_runtime.py
运行时默认配置和 det_p5_tta.py
TTA的默认配置,这些是原始配置。在同一个文件夹,比如 configs/yolov8
中,官方建议只有一个对应的原始配置文件以确保最大继承深度为3。
大部分情况下,可以直接继承现有的方法,比如 yolov8_s_syncbn_fast_8xb16-500e_coco.py
这个就是最基本的现有方法,你会发现 m
,l
,x
等模型就是集成于上一个方法。而且模型size的变化也是基于 deepen_factor
和 widen_factor
的变化,所以只需要制定 _base_ = yolov8_s_syncbn_fast_8xb16-500e_coco.py
继承基础结构后再修改必要的网络参数即可实现自定义或修改网络的功能。
如果要忽略基础配置文件的一些内容,可以设置 _delete_=True
参考文章
[1] https://www.cnblogs.com/jimchen1218/p/14315008.html
[2] https://zhuanlan.zhihu.com/p/408610877
[3] https://zhuanlan.zhihu.com/p/526036013
[4] https://www.mathworks.com/help/vision/ug/getting-started-with-yolo-v4.html
[5] https://pytorch-tutorial.readthedocs.io/en/latest/tutorial/chapter04_advanced/4_1_fine-tuning/
[6] https://arxiv.org/abs/1904.11492
[7] https://arxiv.org/abs/1711.07971
[8] https://zhuanlan.zhihu.com/p/341908571
[9] https://github.com/open-mmlab/mmyolo/blob/main/docs/zh_cn/tutorials/config.md