Merge pull request #1360 from cuicheng01/develop

update docs
pull/1361/head
cuicheng01 2021-10-31 19:21:13 +08:00 committed by GitHub
commit 67cd9eff31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1503 additions and 0 deletions

View File

@ -0,0 +1,262 @@
# FAQ
## 写在前面
* 我们收集整理了开源以来在issues和用户群中的常见问题并且给出了简要解答旨在为图像分类的开发者提供一些参考也希望帮助大家少走一些弯路。
* 图像分类领域大佬众多,模型和论文更新速度也很快,本文档回答主要依赖有限的项目实践,难免挂一漏万,如有遗漏和不足,也希望有识之士帮忙补充和修正,万分感谢。
## PaddleClas常见问题汇总
* [图像分类30个问题](#图像分类30个问题)
* [基础知识](#基础知识)
* [模型训练相关](#模型训练相关)
* [数据相关](#数据相关)
* [模型推理与预测相关](#模型推理与预测相关)
* [PaddleClas使用问题](#PaddleClas使用问题)
<a name="图像分类30个问题"></a>
## 图像分类30个问题
<a name="基础知识"></a>
### 基础知识
>>
* Q: 图像分类领域常用的分类指标有几种
* A:
* 对于单个标签的图像分类问题仅包含1个类别与背景评估指标主要有AccuracyPrecisionRecallF-score等令TP(True Positive)表示将正类预测为正类FP(False Positive)表示将负类预测为正类TN(True Negative)表示将负类预测为负类FN(False Negative)表示将正类预测为负类。那么Accuracy=(TP + TN) / NUMPrecision=TP /(TP + FP)Recall=TP /(TP + FN)。
* 对于类别数大于1的图像分类问题评估指标主要有Accuary和Class-wise AccuracyAccuary表示所有类别预测正确的图像数量占总图像数量的百分比Class-wise Accuracy是对每个类别的图像计算Accuracy然后再对所有类别的Accuracy取平均得到。
>>
* Q: 怎样根据自己的任务选择合适的模型进行训练?
* A: 如果希望在服务器部署或者希望精度尽可能地高对模型存储大小或者预测速度的要求不是很高那么推荐使用ResNet_vd、Res2Net_vd、DenseNet、Xception等适合于服务器端的系列模型如果希望在移动端侧部署则推荐使用MobileNetV3、GhostNet等适合于移动端的系列模型。同时我们推荐在选择模型的时候可以参考[模型库](../models)中的速度-精度指标图。
>>
* Q: 如何进行参数初始化,什么样的初始化可以加快模型收敛?
* A: 众所周知参数的初始化可以影响模型的最终性能。一般来说如果目标数据集不是很大建议使用ImageNet-1k训练得到的预训练模型进行初始化。如果是自己手动设计的网络或者暂时没有基于ImageNet-1k训练得到的预训练权重可以使用Xavier初始化或者MSRA初始化其中Xavier初始化是针对Sigmoid函数提出的对RELU函数不太友好网络越深各层输入的方差越小网络越难训练所以当神经网络中使用较多RELU激活函数时推荐使用MSRA初始化。
>>
* Q: 针对深度神经网络参数冗余的问题,目前有哪些比较好的解决办法?
* A: 目前有几种主要的方法对模型进行压缩减少模型参数冗余的问题如剪枝、量化、知识蒸馏等。模型剪枝指的是将权重矩阵中相对不重要的权值剔除然后再重新对网络进行微调模型量化指的是一种将浮点计算转成低比特定点计算的技术如8比特、4比特等可以有效的降低模型计算强度、参数大小和内存消耗。知识蒸馏是指使用教师模型(teacher model)去指导学生模型(student model)学习特定任务,保证小模型在参数量不变的情况下,性能有较大的提升,甚至获得与大模型相似的精度指标。
>>
* Q: 怎样在其他任务,如目标检测、图像分割、关键点检测等任务中选择比较合适的分类模型作为骨干网络?
* A: 在不考虑速度的情况下在大部分的任务中推荐使用精度更高的预训练模型和骨干网络PaddleClas中开源了一系列的SSLD知识蒸馏预训练模型如ResNet50_vd_ssld, Res2Net200_vd_26w_4s_ssld等在模型精度和速度方面都是非常有优势的推荐大家使用。对于一些特定的任务如图像分割或者关键点检测等任务对图像分辨率的要求比较高那么更推荐使用HRNet等能够同时兼顾网络深度和分辨率的神经网络模型PaddleClas也提供了HRNet_W18_C_ssld、HRNet_W48_C_ssld等精度非常高的HRNet SSLD蒸馏系列预训练模型大家可以使用这些精度更高的预训练模型与骨干网络提升自己在其他任务上的模型精度。
>>
* Q: 注意力机制是什么?目前有哪些比较常用的注意力机制方法?
* A: 注意力机制Attention Mechanism源于对人类视觉的研究。将注意力机制用在计算机视觉任务上可以有效捕捉图片中有用的区域从而提升整体网络性能。目前比较常用的有[SE block](https://arxiv.org/abs/1709.01507)、[SK-block](https://arxiv.org/abs/1903.06586)、[Non-local block](https://arxiv.org/abs/1711.07971)、[GC block](https://arxiv.org/abs/1904.11492)、[CBAM](https://arxiv.org/abs/1807.06521)等,核心思想就是去学习特征图在不同区域或者不同通道中的重要性,从而让网络更加注意显著性的区域。
<a name="模型训练相关"></a>
### 模型训练相关
>>
* Q: 使用深度卷积网络做图像分类如果训练一个拥有1000万个类的模型会碰到什么问题
* A: 因为FC层参数很多内存/显存/模型的存储占用都会大幅增大模型收敛速度也会变慢一些。建议在这种情况下再最后的FC层前加一层维度较小的FC这样可以大幅减少模型的存储大小。
>>
* Q: 训练过程中,如果模型收敛效果很差,可能的原因有哪些呢?
* A: 主要有以下几个可以排查的地方1应该检查数据标注确保训练集和验证集的数据标注没有问题。2可以试着调整一下学习率初期可以以10倍为单位进行调节过大训练震荡或者过小收敛太慢的学习率都可能导致收敛效果差。3数据量太大选择的模型太小难以学习所有数据的特征。4可以看下数据预处理的过程中是否使用了归一化如果没有使用归一化操作收敛速度可能会比较慢。5如果数据量比较小可以试着加载PaddleClas中提供的基于ImageNet-1k数据集的预训练模型这可以大大提升训练收敛速度。6数据集存在长尾问题可以参考[数据长尾问题解决方案](#jump)。
>>
* Q: 训练图像分类任务时,该怎么选择合适的优化器?
* A: 优化器的目的是为了让损失函数尽可能的小从而找到合适的参数来完成某项任务。目前业界主要用到的优化器有SGD、RMSProp、Adam、AdaDelt等其中由于带momentum的SGD优化器广泛应用于学术界和工业界所以我们发布的模型也大都使用该优化器来实现损失函数的梯度下降。带momentum的SGD优化器有两个劣势其一是收敛速度慢其二是初始学习率的设置需要依靠大量的经验然而如果初始学习率设置得当并且迭代轮数充足该优化器也会在众多的优化器中脱颖而出使得其在验证集上获得更高的准确率。一些自适应学习率的优化器如Adam、RMSProp等收敛速度往往比较快但是最终的收敛精度会稍差一些。如果追求更快的收敛速度我们推荐使用这些自适应学习率的优化器如果追求更高的收敛精度我们推荐使用带momentum的SGD优化器。
>>
* Q: 当前主流的学习率下降策略有哪些?一般需要怎么选择呢?
* A: 学习率是通过损失函数的梯度调整网络权重的超参数的速度。学习率越低损失函数的变化速度就越慢。虽然使用低学习率可以确保不会错过任何局部极小值但也意味着将花费更长的时间来进行收敛特别是在被困在高原区域的情况下。在整个训练过程中我们不能使用同样的学习率来更新权重否则无法到达最优点所以需要在训练过程中调整学习率的大小。在训练初始阶段由于权重处于随机初始化的状态损失函数相对容易进行梯度下降所以可以设置一个较大的学习率。在训练后期由于权重参数已经接近最优值较大的学习率无法进一步寻找最优值所以需要设置一个较小的学习率。在训练整个过程中很多研究者使用的学习率下降方式是piecewise_decay即阶梯式下降学习率如在ResNet50标准的训练中我们设置的初始学习率是0.1每30epoch学习率下降到原来的1/10一共迭代120epoch。除了piecewise_decay很多研究者也提出了学习率的其他下降方式如polynomial_decay多项式下降、exponential_decay指数下降,cosine_decay余弦下降其中cosine_decay无需调整超参数鲁棒性也比较高所以成为现在提高模型精度首选的学习率下降方式。Cosine_decay和piecewise_decay的学习率变化曲线如下图所示容易观察到在整个训练过程中cosine_decay都保持着较大的学习率所以其收敛较为缓慢但是最终的收敛效果较peicewise_decay更好一些。
![](../../images/models/lr_decay.jpeg)
>>
* Q: Warmup学习率策略是什么一般用在什么样的场景中
* A: Warmup策略顾名思义就是让学习率先预热一下在训练初期我们不直接使用最大的学习率而是用一个逐渐增大的学习率去训练网络当学习率增大到最高点时再使用学习率下降策略中提到的学习率下降方式衰减学习率的值。如果使用较大的batch_size训练神经网络时我们建议您使用warmup策略。实验表明在batch_size较大时warmup可以稳定提升模型的精度。在训练MobileNetV3等batch_size较大的实验中我们默认将warmup中的epoch设置为5即先用5epoch将学习率从0增加到最大值再去做相应的学习率衰减。
>>
* Q: 什么是`batch size`?在模型训练中,怎么选择合适的`batch size`
* A: `batch size`是训练神经网络中的一个重要的超参数,该值决定了一次将多少数据送入神经网络参与训练。论文[Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour](https://arxiv.org/abs/1706.02677),当`batch size`的值与学习率的值呈线性关系时收敛精度几乎不受影响。在训练ImageNet数据时大部分的神经网络选择的初始学习率为0.1`batch size`是256所以根据实际的模型大小和显存情况可以将学习率设置为0.1*k,batch_size设置为256*k。在实际任务中也可以将该设置作为初始参数进一步调节学习率参数并获得更优的性能。
>>
* Q: weight_decay是什么怎么选择合适的weight_decay呢
* A: 过拟合是机器学习中常见的一个名词简单理解即为模型在训练数据上表现很好但在测试数据上表现较差在卷积神经网络中同样存在过拟合的问题为了避免过拟合很多正则方式被提出其中weight_decay是其中一个广泛使用的避免过拟合的方式。在使用SGD优化器时weight_decay等价于在最终的损失函数后添加L2正则化L2正则化使得网络的权重倾向于选择更小的值最终整个网络中的参数值更趋向于0模型的泛化性能相应提高。在各大深度学习框架的实现中该值表达的含义是L2正则前的系数在paddle框架中该值的名称是l2_decay所以以下都称其为l2_decay。该系数越大表示加入的正则越强模型越趋于欠拟合状态。在训练ImageNet的任务中大多数的网络将该参数值设置为1e-4在一些小的网络如MobileNet系列网络中为了避免网络欠拟合该值设置为1e-5~4e-5之间。当然该值的设置也和具体的数据集有关系当任务的数据集较大时网络本身趋向于欠拟合状态可以将该值适当减小当任务的数据集较小时网络本身趋向于过拟合状态可以将该值适当增大。下表展示了MobileNetV1_x0_25在ImageNet-1k上使用不同l2_decay的精度情况。由于MobileNetV1_x0_25是一个比较小的网络所以l2_decay过大会使网络趋向于欠拟合状态所以在该网络中相对1e-43e-5是更好的选择。
| 模型 | L2_decay | Train acc1/acc5 | Test acc1/acc5 |
|:--:|:--:|:--:|:--:|
| MobileNetV1_x0_25 | 1e-4 | 43.79%/67.61% | 50.41%/74.70% |
| MobileNetV1_x0_25 | 3e-5 | 47.38%/70.83% | 51.45%/75.45% |
>>
* Q: 标签平滑(label_smoothing)指的是什么?有什么效果呢?一般适用于什么样的场景中?
* A: Label_smoothing是深度学习中的一种正则化方法其全称是 Label Smoothing Regularization(LSR)即标签平滑正则化。在传统的分类任务计算损失函数时是将真实的one hot标签与神经网络的输出做相应的交叉熵计算而label_smoothing是将真实的one hot标签做一个标签平滑的处理使得网络学习的标签不再是一个hard label而是一个有概率值的soft label其中在类别对应的位置的概率最大其他位置概率是一个非常小的数。具体的计算方式参见论文[2]。在label_smoothing里有一个epsilon的参数值该值描述了将标签软化的程度该值越大经过label smoothing后的标签向量的标签概率值越小标签越平滑反之标签越趋向于hard label在训练ImageNet-1k的实验里通常将该值设置为0.1。
在训练ImageNet-1k的实验中我们发现ResNet50大小级别及其以上的模型在使用label_smooting后精度有稳定的提升。下表展示了ResNet50_vd在使用label_smoothing前后的精度指标。同时由于label_smoohing相当于一种正则方式在相对较小的模型上精度提升不明显甚至会有所下降下表展示了ResNet18在ImageNet-1k上使用label_smoothing前后的精度指标。可以明显看到在使用label_smoothing后精度有所下降。
| 模型 | Use_label_smoothing | Test acc1 |
|:--:|:--:|:--:|
| ResNet50_vd | 0 | 77.9% |
| ResNet50_vd | 1 | 78.4% |
| ResNet18 | 0 | 71.0% |
| ResNet18 | 1 | 70.8% |
>>
* Q: 在训练的时候怎么通过训练集和验证集的准确率或者loss确定进一步的调优策略呢
* A: 在训练网络的过程中通常会打印每一个epoch的训练集准确率和验证集准确率二者刻画了该模型在两个数据集上的表现。通常来说训练集的准确率比验证集准确率微高或者二者相当是比较不错的状态。如果发现训练集的准确率比验证集高很多说明在这个任务上已经过拟合需要在训练过程中加入更多的正则如增大l2_decay的值加入更多的数据增广策略加入label_smoothing策略等如果发现训练集的准确率比验证集低一些说明在这个任务上可能欠拟合需要在训练过程中减弱正则效果如减小l2_decay的值减少数据增广方式增大图片crop区域面积减弱图片拉伸变换去除label_smoothing等。
>>
* Q: 怎么使用已有的预训练模型提升自己的数据集的精度呢?
* A: 在现阶段计算机视觉领域中加载预训练模型来训练自己的任务已成为普遍的做法相比从随机初始化开始训练加载预训练模型往往可以提升特定任务的精度。一般来说业界广泛使用的预训练模型是通过训练128万张图片1000类的ImageNet-1k数据集得到的该预训练模型的fc层权重是是一个k\*1000的矩阵其中k是fc层以前的神经元数在加载预训练权重时无需加载fc层的权重。在学习率方面如果您的任务训练的数据集特别小如小于1千张我们建议你使用较小的初始学习率如0.001batch_size:256,下同以免较大的学习率破坏预训练权重。如果您的训练数据集规模相对较大大于10万我们建议你尝试更大的初始学习率如0.01或者更大。
<a name="数据相关"></a>
### 数据相关
>>
* Q: 图像分类的数据预处理过程一般包括哪些步骤?
* A: 以在ImageNet-1k数据集上训练ResNet50为例一张图片被输入进网络主要有图像解码、随机裁剪、随机水平翻转、标准化、数据重排组batch并送进网络这几个步骤。图像解码指的是将图片文件读入到内存中随机裁剪指的是将读入的图像随机拉伸并裁剪到长宽均为224的图像随机水平翻转指的是对裁剪后的图片以0.5的概率进行水平翻转,标准化指的是将图片每个通道的数据通过去均值实现中心化的处理,使得数据尽可能符合`N(0,1)`的正态分布,数据重排指的是将数据由`[224,224,3]`的格式变为`[3,224,224]`的格式组batch指的是将多幅图像组成一个批数据送进网络进行训练。
>>
* Q: 随机裁剪是怎么影响小模型训练的性能的?
* A: 在ImageNet-1k数据的标准预处理中随机裁剪函数中定义了scale和ratio两个值两个值分别确定了图片crop的大小和图片的拉伸程度其中scale的默认取值范围是0.08-1(lower_scale-upper_scale),ratio的默认取值范围是3/4-4/3(lower_ratio-upper_ratio)。在非常小的网络训练中此类数据增强会使得网络欠拟合导致精度有所下降。为了提升网络的精度可以使其数据增强变的更弱即增大图片的crop区域或者减弱图片的拉伸变换程度。我们可以分别通过增大lower_scale的值或缩小lower_ratio与upper_scale的差距来实现更弱的图片变换。下表列出了使用不同lower_scale训练MobileNetV2_x0_25的精度可以看到增大图片的crop区域面积后训练精度和验证精度均有提升。
| 模型 | Scale取值范围 | Train_acc1/acc5 | Test_acc1/acc5 |
|:--:|:--:|:--:|:--:|
| MobileNetV2_x0_25 | [0.08,1] | 50.36%/72.98% | 52.35%/75.65% |
| MobileNetV2_x0_25 | [0.2,1] | 54.39%/77.08% | 53.18%/76.14% |
>>
* Q: 数据量不足的情况下,目前有哪些常见的数据增广方法来增加训练样本的丰富度呢?
* A: PaddleClas中将目前比较常见的数据增广方法分为了三大类分别是图像变换类、图像裁剪类和图像混叠类图像变换类主要包括AutoAugment和RandAugment图像裁剪类主要包括CutOut、RandErasing、HideAndSeek和GridMask图像混叠类主要包括Mixup和Cutmix更详细的关于数据增广的介绍可以参考[数据增广章节](../algorithm_introduction/DataAugmentation.md)。
>>
* Q: 对于遮挡情况比较常见的图像分类场景,该使用什么数据增广方法去提升模型的精度呢?
* A: 在训练的过程中可以尝试对训练集使用CutOut、RandErasing、HideAndSeek和GridMask等裁剪类数据增广方法让模型也能够不止学习到显著区域也能关注到非显著性区域从而在遮挡的情况下也能较好地完成识别任务。
>>
* Q: 对于色彩变换情况比较复杂的情况下,应该使用哪些数据增广方法提升模型精度呢?
* A: 可以考虑使用AutoAugment或者RandAugment的数据增广策略这两种策略中都包括了锐化、直方图均衡化等丰富的颜色变换可以让模型在训练的过程中对这些变换更加鲁棒。
>>
* Q: Mixup和Cutmix的工作原理是什么为什么它们也是非常有效的数据增广方法
* A: Mixup通过线性叠加两张图片生成新的图片对应label也进行线性叠加用以训练Cutmix则是从一幅图中随机裁剪出一个 感兴趣区域(ROI)然后覆盖当前图像中对应的区域label也按照图像面积比例进行线性叠加。它们其实也是生成了和训练集不同的样本和label并让网络去学习从而扩充了样本的丰富度。
>>
* Q: 对于精度要求不是那么高的图像分类任务,大概需要准备多大的训练数据集呢?
* A: 训练数据的数量和需要解决问题的复杂度有关系。难度越大精度要求越高则数据集需求越大而且一般情况实际中的训练数据越多效果越好。当然一般情况下在加载预训练模型的情况下每个类别包括10-20张图像即可保证基本的分类效果不加载预训练模型的情况下每个类别需要至少包含100-200张图像以保证基本的分类效果。
>>
* Q: <span id="jump">对于长尾分布的数据集,目前有哪些比较常用的方法?</span>
* A: 1可以对数据量比较少的类别进行重采样增加其出现的概率2可以修改loss增加图像较少对应的类别的图片的loss权重3可以借鉴迁移学习的方法从常见类别中学习通用知识然后迁移到少样本的类别中。
<a name="模型推理与预测相关"></a>
### 模型推理与预测相关
>>
* Q: 有时候图像中只有小部分区域是所关注的前景物体,直接拿原图来进行分类的话,识别效果很差,这种情况要怎么做呢?
* A: 可以在分类之前先加一个主体检测的模型将前景物体检测出来之后再进行分类可以大大提升最终的识别效果。如果不考虑时间成本也可以使用multi-crop的方式对所有的预测做融合来决定最终的类别。
>>
* Q: 目前推荐的,模型预测方式有哪些?
* A: 在模型训练完成之后推荐使用导出的固化模型inference model基于Paddle预测引擎进行预测目前支持python inference与cpp inference。如果希望基于服务化部署预测模型那么推荐使用HubServing的部署方式。
>>
* Q: 模型训练完成之后,有哪些比较合适的预测方法进一步提升模型精度呢?
* A: 1可以使用更大的预测尺度比如说训练的时候使用的是224那么预测的时候可以考虑使用288或者320这会直接带来0.5%左右的精度提升。2可以使用测试时增广的策略Test Time Augmentation, TTA)将测试集通过旋转、翻转、颜色变换等策略创建多个副本并分别预测最后将所有的预测结果进行融合这可以大大提升预测结果的精度和鲁棒性。3当然也可以使用多模型融合的策略将多个模型针对相同图片的预测结果进行融合。
>>
* Q: 多模型融合的时候,该怎么选择合适的模型进行融合呢?
* A: 在不考虑预测速度的情况下建议选择精度尽量高的模型同时建议选择不同结构或者系列的模型进行融合比如在精度相似的情况下ResNet50_vd与Xception65的模型融合结果往往比ResNet50_vd与ResNet101_vd的模型融合结果要好一些。
>>
* Q: 使用固定的模型进行预测时有哪些比较常用的加速方法?
* A: 1使用性能更优的GPU进行预测2增大预测的batch size3使用TenorRT以及FP16半精度浮点数等方法进行预测。
<a name="PaddleClas使用问题"></a>
## PaddleClas使用问题
>>
* Q: 多卡评估时,为什么每张卡输出的精度指标不相同?
* A: 目前PaddleClas基于fleet api使用多卡在多卡评估时每张卡都是单独读取各自part的数据不同卡中计算的图片是不同的因此最终指标也会有微量差异如果希望得到准确的评估指标可以使用单卡评估。
>>
* Q: 在配置文件的`TRAIN`字段中配置了`mix`的参数,为什么`mixup`的数据增广预处理没有生效呢?
* A: 使用mixup时数据预处理部分与模型输入部分均需要修改因此还需要在配置文件中显式地配置`use_mix: True`,才能使得`mixup`生效。
>>
* Q: 评估和预测时,已经指定了预训练模型所在文件夹的地址,但是仍然无法导入参数,这么为什么呢?
* A: 加载预训练模型时,需要指定预训练模型的前缀,例如预训练模型参数所在的文件夹为`output/ResNet50_vd/19`,预训练模型参数的名称为`output/ResNet50_vd/19/ppcls.pdparams`,则`pretrained_model`参数需要指定为`output/ResNet50_vd/19/ppcls`PaddleClas会自动补齐`.pdparams`的后缀。
>>
* Q: 在评测`EfficientNetB0_small`模型时为什么最终的精度始终比官网的低0.3%左右?
* A: `EfficientNet`系列的网络在进行resize的时候是使用`cubic插值方式`(resize参数的interpolation值设置为2)而其他模型默认情况下为None因此在训练和评估的时候需要显式地指定resize的interpolation值。具体地可以参考以下配置中预处理过程中ResizeImage的参数。
```
VALID:
batch_size: 16
num_workers: 4
file_list: "./dataset/ILSVRC2012/val_list.txt"
data_dir: "./dataset/ILSVRC2012/"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- ResizeImage:
resize_short: 256
interpolation: 2
- CropImage:
size: 224
- NormalizeImage:
scale: 1.0/255.0
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
```
>>
* Q: python2下使用visualdl的时候报出以下错误`TypeError: __init__() missing 1 required positional argument: 'sync_cycle'`,这是为什么呢?
* A: 目前visualdl仅支持在python3下运行visualdl需要是2.0以上的版本如果visualdl版本不对的话可以通过以下方式进行安装`pip3 install visualdl==2.0.0b8 -i https://mirror.baidu.com/pypi/simple`
>>
* Q: 自己在测ResNet50_vd预测单张图片速度的时候发现比官网提供的速度benchmark慢了很多而且CPU速度比GPU速度快很多这个是为什么呢
* A: 模型预测需要初始化初始化的过程比较耗时因此在统计预测速度的时候需要批量跑一批图片去除前若干张图片的预测耗时再统计下平均的时间。GPU比CPU速度测试单张图片速度慢是因为GPU的初始化并CPU要慢很多。
>>
* Q: 在动态图中加载静态图预训练模型的时候,需要注意哪些问题?
* A: 在使用infer.py预测单张图片或者文件夹中的图片时需要注意指定[infer.py](https://github.com/PaddlePaddle/PaddleClas/blob/53c5850df7c49a1bfcd8d989e6ccbea61f406a1d/tools/infer/infer.py#L40)中的`load_static_weights`为True在finetune或者评估的时候需要添加`-o load_static_weights=True`的参数。
>>
* Q: 灰度图可以用于模型训练吗?
* A: 灰度图也可以用于模型训练不过需要修改模型的输入shape为`[1, 224, 224]`此外数据增广部分也需要注意适配一下。不过为了更好地使用PaddleClas代码的话即使是灰度图也建议调整为3通道的图片进行训练RGB通道的像素值相等
>>
* Q: 怎么在windows上或者cpu上面模型训练呢
* A: 可以参考[PaddleClas开始使用教程](https://github.com/PaddlePaddle/PaddleClas/blob/master/docs/zh_CN/tutorials/getting_started.md)详细介绍了在Linux、Windows、CPU等环境中进行模型训练、评估与预测的教程。
>>
* Q: 怎样在模型训练的时候使用label smoothing呢
* A: 可以在配置文件中设置label smoothing epsilon的值`ls_epsilon=0.1`表示设置该值为0.1,若该值为-1则表示不使用label smoothing。
>>
* Q: PaddleClas提供的10W类图像分类预训练模型能否用于模型推断呢
* A: 该10W类图像分类预训练模型没有提供fc全连接层的参数无法用于模型推断目前可以用于模型微调。
>>
* Q: 在使用`tools/infere/predict.py`进行模型预测的时候,报了这个问题:`Error: Pass tensorrt_subgraph_pass has not been registered`,这是为什么呢?
* A: 如果希望使用TensorRT进行模型预测推理的话需要编译带TensorRT的PaddlePaddle编译的时候参考以下的编译方式其中`TENSORRT_ROOT`表示TensorRT的路径。
```
cmake .. \
-DWITH_CONTRIB=OFF \
-DWITH_MKL=ON \
-DWITH_MKLDNN=ON \
-DWITH_TESTING=OFF \
-DCMAKE_BUILD_TYPE=Release \
-DWITH_INFERENCE_API_TEST=OFF \
-DON_INFER=ON \
-DWITH_PYTHON=ON \
-DPY_VERSION=2.7 \
-DTENSORRT_ROOT=/usr/local/TensorRT6-cuda10.0-cudnn7/
make -j16
make inference_lib_dist
```
>>
* Q: 怎样在训练的时候使用自动混合精度(Automatic Mixed Precision, AMP)训练呢?
* A: 可以参考[ResNet50_fp16.yml](https://github.com/PaddlePaddle/PaddleClas/blob/master/configs/ResNet/ResNet50_fp16.yml)这个配置文件;具体地,如果希望自己的配置文件在模型训练的时候也支持自动混合精度,可以在配置文件中添加下面的配置信息。
```
use_fp16: True
amp_scale_loss: 128.0
use_dynamic_loss_scaling: True
```

View File

@ -0,0 +1,372 @@
# 图像分类常见问题汇总 - 2020 第1季
## 目录
* [第1期](#第1期)(2020.11.03)
* [第2期](#第2期)(2020.11.11)
* [第3期](#第3期)(2020.11.18)
* [第4期](#第4期)(2020.12.07)
* [第5期](#第5期)(2020.12.17)
* [第6期](#第6期)(2020.12.30)
<a name="第1期"></a>
## 第1期
### Q1.1: PaddleClas可以用来做什么?
**A**PaddleClas是飞桨为工业界和学术界所准备的一个图像分类任务的工具集助力使用者训练出更好的视觉模型和应用落地。PaddleClas提供了基于图像分类的模型训练、评估、预测、部署全流程的服务方便大家更加高效地学习图像分类。具体地PaddleClas中包含如下一些特性 。
* PaddleClas提供了24个系列的分类网络结构(ResNet, ResNet_vd, MobileNetV3, Res2Net, HRNet等)和训练配置122个预训练模型和性能评估与预测供大家选择并使用。
* PaddleClas提供了TensorRT预测、python inference、c++ inference、Paddle-Lite预测部署等多种预测部署推理方案在方便在多种环境中进行部署推理。
* PaddleClas提供了一种简单的SSLD知识蒸馏方案基于该方案蒸馏模型的识别准确率普遍提升3%以上。
* PaddleClas支持AutoAugment、Cutout、Cutmix等8种数据增广算法详细介绍、代码复现和在统一实验环境下的效果评估。
* PaddleClas支持在Windows/Linux/MacOS环境中基于CPU/GPU进行使用。
### Q1.2: ResNet系列模型是什么有哪些模型为什么在服务器端如此推荐ResNet系列模型
**A**: ResNet中创新性地引入了残差结构通过堆叠多个残差结构从而构建了ResNet网络。实验表明使用残差块可以有效地提升收敛速度和精度PaddleClas中ResNet从小到达依次有包含18、34、50、101、152、200层的ResNet结构ResNet系列模型于2015年被提出在不同的应用场景中如分类、检测、分割等都已经验证过其有效性业界也早已对其进行了大量优化该系列模型在速度和精度方面都有着非常明显的优势对基于TensorRT以及FP16的预测支持得也很好因而推荐大家使用ResNet系列模型由于其模型所占存储相对较大因此常用于服务器端。更多关于ResNet模型的介绍可以参考论文[Deep Residual Learning for Image Recognition](https://arxiv.org/abs/1512.03385)。
### Q1.3: ResNet_vd和ResNet、ResNet_vc结构有什么区别呢
**A**:
ResNet_va至vd的结构如下图所示ResNet最早提出时为va结构在降采样残差模块这个部分在左边的特征变换通路中(Path A)第一个1x1卷积部分就行了降采样从而导致信息丢失卷积的kernel size为1stride为2输入特征图中 有部分特征没有参与卷积的计算在vb结构中把降采样的步骤从最开始的第一个1x1卷积调整到中间的3x3卷积中从而避免了信息丢失的问题PaddleClas中的ResNet模型默认就是ResNet_vbvc结构则是将最开始这个7x7的卷积变成3个3x3的卷积在感受野不变的情况下计算量和存储大小几乎不变而且实验证明精度相对于vb结构有所提升vd结构是修改了降采样残差模块右边的特征通路(Path B)。把降采样的过程由平均池化这个操作去替代了,这一系列的改进(va->vd)几乎没有带来新增的预测耗时结合适当的训练策略比如说标签平滑以及mixup数据增广精度可以提升高达2.7%。
<div align="center">
<img src="../../images/faq/ResNet_vabcd_structure.png" width="800">
</div>
### Q1.4 如果确定使用ResNet系列模型怎么根据实际的场景需求选用不同的模型呢
**A**:
ResNet系列模型中相比于其他模型ResNet_vd模型在预测速度几乎不变的情况下精度有非常明显的提升因此推荐大家使用ResNet_vd系列模型。
下面给出了batch size=4的情况下在T4 GPU上不同模型的的预测耗时、flops、params与精度的变化曲线可以根据自己自己的实际部署场景中的需求去选择合适的模型如果希望模型存储大小尽可能小或者预测速度尽可能快则可以使用ResNet18_vd模型如果希望获得尽可能高的精度则建议使用ResNet152_vd或者ResNet200_vd模型。更多关于ResNet系列模型的介绍可以参考文档[ResNet及其vd系列模型文档](../models/ResNet_and_vd.md)。
* 精度-预测速度变化曲线
<div align="center">
<img src="../../images/models/T4_benchmark/t4.fp32.bs4.ResNet.png" width="800">
</div>
* 精度-params变化曲线
<div align="center">
<img src="../../images/models/T4_benchmark/t4.fp32.bs4.ResNet.params.png" width="800">
</div>
* 精度-flops变化曲线
<div align="center">
<img src="../../images/models/T4_benchmark/t4.fp32.bs4.ResNet.flops.png" width="800">
</div>
### Q1.5 在网络中的block里conv-bn-relu是固定的形式吗
**A**: 在batch-norm出现之前主流的卷积神经网络的固定形式是conv-relu。在现阶段的卷积神经网络中conv-bn-relu是大部分网络中block的固定形式这样的设计是相对鲁棒的结构此外DenseNet中的block选用的是bn-relu-conv的形式ResNet-V2中也使用的是这种组合方式。在MobileNetV2中为了不丢失信息部分block中间的层没有使用relu激活函数选用的是conv-bn的形式。
### Q1.6 ResNet34与ResNet50的区别
**A**: ResNet系列中有两种不同的block分别是basic-block和bottleneck-block堆叠较多这样的block组成了ResNet网络。basic-block是带有shortcut的两个3x3的卷积核的堆叠bottleneck-block是带有shortcut的1x1卷积核、3x3卷积核、1x1卷积核的堆叠所以basic-block中有两层bottleneck-block有三层。ResNet34和ResNet50中堆叠的block数相同但是堆叠的种类分别是basic-block和bottleneck-block。
### Q1.7 大卷积核一定可以带来正向收益吗?
**A**: 不一定,将网络中的所有卷积核都增大未必会带来性能的提升,甚至会有有损性能,在论文[MixConv: Mixed Depthwise Convolutional Kernels](https://arxiv.org/abs/1907.09595)
中指出,在一定范围内提升卷积核大小对精度的提升有正向作用,但是超出后会有损精度。所以考虑到模型的大小、计算量等问题,一般不选用大的卷积核去设计网络。
<a name="第2期"></a>
## 第2期
### Q2.1: PaddleClas如何训练自己的backbone
**A**:具体流程如下:
* 首先在ppcls/modeling/architectures/文件夹下新建一个自己的模型结构文件即你自己的backbone模型搭建可以参考resnet.py;
* 然后在ppcls/modeling/\_\_init\_\_.py中添加自己设计的backbone的类;
* 其次配置训练的yaml文件此处可以参考configs/ResNet/ResNet50.yaml;
* 最后启动训练即可。
### Q2.2: 如何利用已有的模型和权重对自己的分类任务进行迁移?
**A**: 具体流程如下:
* 首先好的预训练模型往往会有更好的迁移效果所以建议选用精度较高的预训练模型PaddleClas提供了一系列业界领先的预训练模型建议使用
* 其次要根据迁移的数据集的规模来确定训练超参数一般超参数需要调试才可以寻找到一个局部最优值如果没有相关经验建议先从learning rate开始调起一般来说规模较小的数据集使用较小的learning rate如0.001另外建议学习率使用warmup策略避免过大的学习率破坏预训练模型的权重。在迁移过程中也可以设置backbone中不同层的学习率往往从网络的头部到尾补学习率逐渐减小效果较好。在数据集规模较小的时候也可以使用数据增强策略PaddleClas提供了8中强有力的数据增强策略为更高的精度保驾护航。
* 训练结束后,可以反复迭代上述过程,直到寻找到局部最优值。
### Q2.3: PaddleClas中configs下的默认参数适合任何一个数据集吗
**A**: PaddleClas中的configs下的默认参数是ImageNet-1k的训练参数这个参数并不适合所有的数据集具体数据集需要在此基础上进一步调试调试方法会在之后出一个单独的faq敬请期待。
### Q2.4 PaddleClas中的不同的模型使用了不同的分辨率标配的应该是多少呢
**A**: PaddleClas严格遵循了论文作者的使用的分辨率。自2012年AlexNet以来大多数的卷积神经网络在ImageNet上训练的分辨率为224x224Google在设计InceptionV3的时候为了适应网络结构将分辨率调至299x299之后其推出的Xception、InceptionV4也是使用的该分辨率。此外在EfficeintNet中作者分析了不同规模的网络应该使用不同的分辨率所以该系列网络中每个不同大小的网络都使用了不同的分辨率。在实际使用场景中推荐使用默认的分辨率当然层数较深或者宽度较大的网络也可以尝试使用更大的分辨率。
### Q2.5 PaddleClas中提供了很多ssld模型其应用的价值是
**A**: PaddleClas中提供了很多ssld预训练模型其通过半监督知识蒸馏的方法获得了更好的预训练权重在迁移任务或者下游视觉任务中无须替换结构文件、只需要替换精度更高的ssld预训练模型即可提升精度如在PaddleSeg中[HRNet](https://github.com/PaddlePaddle/PaddleSeg/blob/release/v0.7.0/docs/model_zoo.md)使用了ssld预训练模型的权重后精度大幅度超越业界同样的模型的精度在PaddleDetection中[PP-YOLO](https://github.com/PaddlePaddle/PaddleDetection/blob/release/0.4/configs/ppyolo/README_cn.md)使用了ssld预训练权重后在较高的baseline上仍有进一步的提升。使用ssld预训练权重做分类的迁移表现也很抢眼在[SSLD蒸馏策略](../advanced_tutorials/distillation/distillation.md)部分介绍了知识蒸馏对于分类任务迁移的收益。
<a name="第3期"></a>
## 第3期
### Q3.1: DenseNet模型相比于ResNet有什么改进呢有哪些特点或者应用场景呢
**A**: DenseNet相比于ResNet设计了一个更激进的密集连接机制通过考虑特征重用和旁路的设置进一步减少了参数量而且从一定程度上缓解了梯度弥散的问题因为引入了更加密集的连接因此模型更容易训练而且具有一定的正则化效果。在数据量不是很多的图像分类场景中DenseNet是一个不错的选择。更多关于DenseNet的介绍与系列模型可以参考[DenseNet模型文档](../models/DPN_DenseNet.md)。
### Q3.2: DPN网络相比于DenseNet有哪些改进呢
**A**DPN的全称是Dual Path Networks即双通道网络。该网络是由DenseNet和ResNeXt结合的一个网络其证明了DenseNet能从靠前的层级中提取到新的特征而ResNeXt本质上是对之前层级中已提取特征的复用。作者进一步分析发现ResNeXt对特征有高复用率但冗余度低DenseNet能创造新特征但冗余度高。结合二者结构的优势作者设计了DPN网络。最终DPN网络在同样FLOPS和参数量下取得了比ResNeXt与DenseNet更好的结果。更多关于DPN的介绍与系列模型可以参考[DPN模型文档](../models/DPN_DenseNet.md)。
### Q3.3: 怎么使用多个模型进行预测融合呢?
**A** 使用多个模型进行预测的时候建议首先将预训练模型导出为inference模型这样可以摆脱对网络结构定义的依赖可以参考[模型导出脚本](../../../tools/export_model.py)进行模型导出,之后再参考[inference模型预测脚本](../../../tools/infer/predict.py)进行预测即可在这里需要根据自己使用模型的数量创建多个predictor。
### Q3.4: PaddleClas中怎么增加自己的数据增广方法呢
**A**
* 对于单张图像的增广,可以参考[基于单张图片的数据增广脚本](../../../ppcls/data/preprocess/ops),参考`ResizeImage`或者`CropImage`等数据算子的写法,创建一个新的类,然后在`__call__`中,实现对应的增广方法即可。
* 对于一个batch图像的增广可以参考[基于batch数据的数据增广脚本](../../../ppcls/data/preprocess/batch_ops),参考`MixupOperator`或者`CutmixOperator`等数据算子的写法,创建一个新的类,然后在`__call__`中,实现对应的增广方法即可。
## Q3.5: 怎么进一步加速模型训练过程呢?
**A**
* 可以使用自动混合精度进行训练这在精度几乎无损的情况下可以有比较明显的速度收益以ResNet50为例PaddleClas中使用自动混合精度训练的配置文件可以参考[ResNet50_fp16.yml](../../../ppcls/configs/ResNet/ResNet50_fp16.yml),主要就是需要在标准的配置文件中添加以下几行
```
use_fp16: True
amp_scale_loss: 128.0
use_dynamic_loss_scaling: True
```
* 可以开启dali将数据预处理方法放在GPU上运行在模型比较小时reader耗时占比更高一些开启dali会带来比较明显的精度收益在训练的时候添加`-o use_dali=True`即可使用dali进行训练更多关于dali 安装与介绍可以参考:[dali安装教程](https://docs.nvidia.com/deeplearning/dali/user-guide/docs/installation.html#nightly-builds)。
<a name="第4期"></a>
## 第4期
### Q4.1: PaddlePaddle 的模型文件都有哪几种?
**A**:
* PaddlePaddle保存的模型相关文件有两类
* 一类是用于*推理部署*的文件,包括后缀名为“`pdiparams`”、“`model`”的文件,其中“`pdiparams`”文件存储了模型参数信息,“`model`”文件存储了模型网络结构信息,对于推理部署文件,使用`paddle.jit.save`与`paddle.jit.load`接口进行保存、加载。
* 另一类模型相关文件则是用于*训练调优*过程中,包括后缀名为“`pdparams`”和“`pdopt`”的文件,其中“`pdparams`”文件存储了训练过程中的模型参数信息,“`pdopt`”文件存储了模型训练过程中的优化器信息,对于训练调优文件,使用`paddle.save`与`paddle.load`接口进行保存、加载。
* 利用推理部署文件,即可构建模型网络结构并加载模型参数,用于预测,利用训练调优文件,即可加载模型参数、优化器信息,用于恢复训练过程。
### Q4.2: HRNet的创新点体现在哪里
**A**:
* 在图像分类领域,大部分神经网络的设计思想是提取图像的高维特征,具体来说,通常输入图像的空间分辨率较高,通过多层卷积、池化,可以逐步得到空间分辨率更低,但是维度更高的特征图,然后可用于分类等场景。
* 然而*HRNet*的作者认为这种逐步降低空间分辨率的设计思想并不适合目标检测(图像区域层次的分类任务)、语义分割(图像像素层次的分类任务)等场景,因为空间分辨率在逐步降低的过程中,会丢失很多信息,最终学习得到的特征难以表达原始图像在高空间分辨率的信息,而区域层次分类任务和像素层次分类任务都对空间精度十分敏感。
* 因此*HRNet*的作者提出了并联不同空间分辨率特征图的思想,与此相对,*VGG*等神经网络则是通过不同的卷积池化层来串联不同空间分辨率的特征图。并且,*HRNet*通过连接同等深度、不同空间分辨率的特征图,使得不同空间分辨率特征图的信息可以得到充分交换,具体的网络结构如下图所示。
<div align="center">
<img src="../../images/faq/HRNet.png" width="800">
</div>
### Q4.3: 在HRNet中对于不同空间分辨率的特征图之间是如何建立连接的
**A**:
* 首先,在*HRNet*中,对特征图使用*stride*为*2*的*3 × 3*卷积,可以得到低空间分辨率但是为度更高的特征图;而对低空间分辨率特征图先使用*1 × 1*卷积进行通道数匹配,再使用最近邻插值的方式进行上采样,即可得到与高空间分辨率特征图相同空间分辨率、通道数的特征图;而对于相同空间分辨率的特征图,直接进行恒等映射即可。具体如下图所示。
<div align="center">
<img src="../../images/faq/HRNet_block.png" width="800">
</div>
### Q4.4: 模型中的“SE”表示什么意思
**A**:
* SE表示该模型使用了SE结构。SE结构来自于2017年ImageNet分类比赛的冠军方案*Squeeze-and-Excitation NetworksSENet**SENet*提出的SE结构可以迁移到任何其他网络中。其创新点是通过额外学习*scale*向量作为权重作用到特征图上,*scale*向量维度与特征图通道数相同,学习到的*scale*向量中每个维度上的数值表示对该维度特征通道的增强或减弱的大小,以此达到对重要的特征通道进行增强,不重要特征通道减弱的效果,从而让提取的特征指向性更强。
### Q4.5: SE结构具体如何实现的
<div align="center">
<img src="../../images/faq/SE_structure.png" width="800">
</div>
**A**:
* *SE*结构具体如上图所示,首先,*Ftr*表示常规的卷积操作,*X*和*U*则是*Ftr*的输入与输出的特征图,在得到特征图*U*后,使用*Fsq*和*Fex*操作求得*scale*向量,*scale*向量维度为*C*,与*U*通道数相同,因此可以通过乘积的方式作用到*U*上,进而得到*X~*。
* 具体地,*Fsq*为*Global Average Pooling*操作,*SENet*作者将其称之为*Squeeze*,因为该操作可以将*U*从*C × H × W*压缩到*C × 1 × 1*,对*Fsq*的输出再做*Fex*操作。
* *Fex*操作表示两次全连接,作者将该操作称为*Excitation*。其中第一次全连接将向量的维度从*1 × 1 × C*压缩到*1 × 1 × C/r*,然后使用*RELU*,再通过第二次全连接将向量的维度恢复到*C*,这样操作的目的是为了减小计算量,*SENet*作者通过实验得出结论:在*r=16*时可以获得增益与计算量之间的平衡。
* 对于*Fsq*部分,关键是求得*C*维的向量,因此不局限于使用*Global Average Pooling*操作,*SENet*作者认为,最终求得的*scale*是按通道分别作用于*U*的,因此需要基于对应通道的信息计算对应的*scale*,故使用了最简单的*Global Average Pooling*操作,最终求得的*scale*向量表示了不同通道之间的分布关系,而忽略了同一个通道中的分布关系。
* 对于*Fex*部分,其作用是为了在每一个*mini batch*上的训练来求得基于所有训练数据的分布。因为我们的训练是在*mini batch*上进行的,而基于全部训练数据求得的*scale*才是最佳的,使用*Fex*部分,可以通过在每个*mini batch*上的训练来求得更为逼近全部训练数据的*scale*。
<a name="第5期"></a>
## 第5期
### Q5.1 如何选择优化器?
**A**:自深度学习发展以来就有很多关于优化器的研究者工作优化器的目的是为了让损失函数尽可能的小从而找到合适的权重来完成某项任务。目前业界主要用到的优化器有SGD、RMSProp、Adam、AdaDelt等其中由于带momentum的SGD优化器广泛应用于学术界和工业界(此处仅限于分类任务)所以我们发布的模型也大都使用该优化器来实现损失函数的梯度下降。带momentum的SGD优化器有两个劣势其一是收敛速度慢其二是初始学习率的设置需要依靠大量的经验然而如果初始学习率设置得当并且迭代轮数充足该优化器也会在众多的优化器中脱颖而出使得其在验证集上获得更高的准确率。一些自适应学习率的优化器如Adam、RMSProp等收敛速度往往比较快但是最终的收敛精度会稍差一些。如果追求更快的收敛速度我们推荐使用这些自适应学习率的优化器如果追求更高的收敛精度我们推荐使用带momentum的SGD优化器。具体到数据集来说
- ImageNet-1k: 建议只使用带momentum的SGD优化器。
- 其他数据集默认加载ImageNet-1k预训练: 加载预训练模型的时候可以考虑使用Adam等优化器效果可能会更好但使用带momentum的SGD优化器是绝对是比较不错的方案。
另外为了进一步加速训练Lookahead优化器也是一个不错的选择在ImageNet-1k上其可以保证在更快的收敛速度下拥有相同的收敛精度但在部分数据集上表现不太稳定需要进一步调参。
### Q5.2 如何设置初始学习率以及学习率下降策略?
**A**:学习率的选择往往和优化器以及数据和任务有关系。学习率决定了网络种权重更新的速度。学习率越低,损失函数的变化速度就越慢。虽然使用低学习率可以确保不会错过任何局部极小值,但也意味着将花费更长的时间来进行收敛,特别是在被困在高原区域的情况下。
在整个训练过程中我们不能使用同样的学习率来更新权重否则无法到达最优点所以需要在训练过程中调整学习率的大小。在训练初始阶段由于权重处于随机初始化的状态损失函数下降较快所以可以设置一个较大的学习率。在训练后期由于权重已经接近最优值较大的学习率无法进一步寻找最优值所以需要设置一个较小的学习率。至于学习率下降策略很多研究者或者从业人员使用的学习率下降方式是piecewise_decay(step_decay)即阶梯式下降学习率此外很多研究者也提出了学习率的其他下降方式如polynomial_decay多项式下降、exponential_decay指数下降,cosine_decay余弦下降其中cosine_decay无需调整超参数鲁棒性也比较高所以成为现在提高模型精度首选的学习率下降方式。
Cosine_decay和piecewise_decay的学习率变化曲线如下图所示容易观察到在整个训练过程中cosine_decay都保持着较大的学习率所以其收敛较为缓慢但是最终的收敛效果较peicewise_decay更好一些。
![](../../images/models/lr_decay.jpeg)
另外从图中我们也可以看到cosine_decay中只有少数轮数使用了较小的学习率这样会影响到最终的精度所以为了使得cosine_decay发挥更好的效果建议迭代更多的轮数。
最后如果使用较大的batch_size训练神经网络时建议您使用warmup策略。Warmup策略顾名思义就是让学习率先预热一下在训练初期不直接使用最大的学习率而是用一个逐渐增大的学习率去训练网络当学习率增大到最高点时再去衰减学习率的值。实验表明在batch_size较大时warmup可以稳定提升模型的精度。具体到数据集来说
- ImageNet-1k:建议batch-size大小为256、初始学习率为0.1cosine-decay下降学习率。
- 其他数据集默认加载ImageNet-1k预训练: 数据集规模越大初始学习率也越大但最好不要超过0.1batch-size为256时候数据集规模越小初始学习率也越小当数据集较小时使用warmup也会带来一定的精度提升学习率下降策略仍旧推荐cosine-decay。
### Q5.3 如何设置batch-size的大小
**A**:Batch_size是训练神经网络中的一个重要的超参数该值决定了一次将多少数据送入神经网络中训练。之前有研究者通过实验发现当batch_size的值与学习率的值呈线性关系时收敛精度几乎不受影响。在训练ImageNet-1k数据时大部分的神经网络选择的初始学习率为0.1batch_size是256。具体到数据集来说
- ImageNet-1k: 学习率设置为0.1\*k,batch_size设置为256\*k。
- 其他数据集默认加载ImageNet-1k预训练: 可以根据实际情况设置如更小的学习率但在调整学习率或者batch-size时要同时调整另外一个值。
### Q5.4 weight_decay是什么怎么设置
**A**:过拟合是机器学习中常见的一个名词简单理解即为模型在训练数据上表现很好但在测试数据上表现较差在图像分类问题中同样存在过拟合的问题为了避免过拟合很多正则方式被提出其中weight_decay是其中一个广泛使用的避免过拟合的方式。当使用SGD优化器时 weight_decay等价于在最终的损失函数后添加L2正则化L2正则化使得网络的权重倾向于选择更小的值最终整个网络中的参数值更趋向于0模型的泛化性能相应提高。在各大深度学习框架的实现中该值表达的含义是L2正则前的系数在飞桨框架中该值的名称是L2Decay所以以下都称其为L2Decay。该系数越大表示加入的正则越强模型越趋于欠拟合状态。具体到数据集来说
- ImageNet-1k大多数的网络将该参数值设置为1e-4在一些小的网络如MobileNet系列网络中为了避免网络欠拟合该值设置为1e-5~4e-5之间。下表展示了MobileNetV1_x0_25在ImageNet-1k上使用不同L2Decay的精度情况。由于MobileNetV1_x0_25是一个比较小的网络所以L2Decay过大会使网络趋向于欠拟合状态所以在该网络中相对1e-43e-5是更好的选择。
| 模型 | L2Decay | Train acc1/acc5 | Test acc1/acc5 |
|:--:|:--:|:--:|:--:|
| MobileNetV1_x0_25 | 1e-4 | 43.79%/67.61% | 50.41%/74.70% |
| MobileNetV1_x0_25 | 3e-5 | 47.38%/70.83% | 51.45%/75.45% |
另外该值的设置也和训练过程中是否使用其他正则化有关系。如果训练过程中的数据预处理比较复杂相当于训练任务变的更难可以将该值适当减小下表展示了在ImageNet-1k上ResNet50在使用RandAugment预处理方式后使用不同L2Decay的精度。容易观察到在任务变难后使用更小的l2_decay有助于模型精度的提升。
| 模型 | L2Decay | Train acc1/acc5 | Test acc1/acc5 |
|:--:|:--:|:--:|:--:|
| ResNet50 | 1e-4 | 75.13%/90.42% | 77.65%/93.79% |
| ResNet50 | 7e-5 | 75.56%/90.55% | 78.04%/93.74% |
- 其他数据集默认加载ImageNet-1k预训练在做迁移任务的时候最好不要改变训练ImageNet-1k时的L2Decay的值即训练得到预训练时的L2Decay值每个backbone对应的L2Decay值都在相应的训练yaml配置文件中一般的数据集只改变学习率足够。
### Q5.5 是否使用label_smoothing如何设置其中的参数值
**A**:Label_smoothing是深度学习中的一种正则化方法其全称是 Label Smoothing Regularization(LSR)即标签平滑正则化。在传统的分类任务计算损失函数时是将真实的one hot标签与神经网络的输出做相应的交叉熵计算而label_smoothing是将真实的one hot标签做一个标签平滑的处理使得网络学习的标签不再是一个hard label而是一个有概率值的soft label其中在类别对应的位置的概率最大其他位置概率是一个非常小的数。在label_smoothing中epsilon参数描述了将标签软化的程度该值越大经过label smoothing后的标签向量的标签概率值越小标签越平滑反之标签越趋向于hard label。具体到数据集来说
- ImageNet-1k在训练ImageNet-1k的实验里通常将该值设置为0.1ResNet50大小级别及其以上的模型在使用label_smooting后精度有稳定的提升。下表展示了ResNet50_vd在使用label_smoothing前后的精度指标。
| 模型 | Use_label_smoothing(0.1) | Test acc1 |
|:--:|:--:|:--:|
| ResNet50_vd | 0 | 77.9% |
| ResNet50_vd | 1 | 78.4% |
同时由于label_smoohing相当于一种正则方式在相对较小的模型上精度提升不明显甚至会有所下降下表展示了ResNet18在ImageNet-1k上使用label_smoothing前后的精度指标。可以明显看到在使用label_smoothing后精度有所下降。
| 模型 | Use_label_smoohing(0.1) | Train acc1/acc5 | Test acc1/acc5 |
|:--:|:--:|:--:|:--:|
| ResNet18 | 0 | 69.81%/87.70% | 70.98%/89.92% |
| ResNet18 | 1 | 68.00%/86.56% | 70.81%/89.89% |
如何在较小的模型中也可以让label-smoothing有效这里有一个技巧即在Global-Average-Pool后接一个1000-2000大小的全连接层该技巧可以与label-smoothing同时作用发挥更好的效果。
- 其他数据集默认加载ImageNet-1k预训练使用label-smooth之后往往都会提升精度规模越小的数据集epsilon值可以越大在一些规模较小的细粒度图像中最佳模型通常是在该值设置到0.4-0.5时获得的。
### Q5.6 默认的图像预处理中random-crop还可以调整吗怎么调整
**A**:在ImageNet-1k数据的标准预处理中random_crop函数中定义了scale和ratio两个值两个值分别确定了图片crop的大小和图片的拉伸程度其中scale的默认取值范围是0.08-1(lower_scale-upper_scale),ratio的默认取值范围是3/4-4/3(lower_ratio-upper_ratio)。在非常小的网络训练中此类数据增强会使得网络欠拟合导致精度有所下降。为了提升网络的精度可以使其数据增强变的更弱即增大图片的crop区域或者减弱图片的拉伸变换程度。可以分别通过增大lower_scale的值或缩小lower_ratio与upper_scale的差距来实现更弱的图片变换。具体到数据集来说
- ImageNet-1k不是特别小的网络建议只用默认值特别小的网络可以调大lower_scale的值增大crop区域面积或者缩小ratio值的范围减弱图像伸缩变换特别大的网络可以调小lower_scale的值减小crop面积或者增大ratio值的范围增强图像伸缩变换。下表列出了使用不同lower_scale训练MobileNetV2_x0_25的精度可以看到增大图片的crop区域面积后训练精度和验证精度均有提升。
| 模型 | Scale取值范围 | Train_acc1/acc5 | Test_acc1/acc5 |
|:--:|:--:|:--:|:--:|
| MobileNetV2_x0_25 | [0.08,1] | 50.36%/72.98% | 52.35%/75.65% |
| MobileNetV2_x0_25 | [0.2,1] | 54.39%/77.08% | 53.18%/76.14% |
- 其他数据集默认加载ImageNet-1k预训练建议使用默认值如果过拟合较严重可以考虑调小lower_scale的值减小crop面积或者增大ratio值的范围增强图像伸缩变换
### Q5.7 目前常用数据增广有哪些?如何选择?
**A**:一般来说数据集的规模对性能影响至关重要但是图片的标注往往比较昂贵所以有标注的图片数量往往比较稀少在这种情况下数据的增广尤为重要。在训练ImageNet-1k的标准数据增广中主要使用了Random_Crop与Random_Flip两种数据增广方式然而近些年越来越多的数据增广方式被提出如cutout、mixup、cutmix、AutoAugment等。实验表明这些数据的增广方式可以有效提升模型的精度。具体到数据集来说
- ImageNet-1k下表列出了ResNet50在8种不同的数据增广方式的表现可以看出相比baseline所有的数据增广方式均有收益其中cutmix是目前最有效的数据增广。更多数据增广的介绍请参考[**数据增广章节**](../advanced_tutorials/image_augmentation/ImageAugment.md)。
| 模型 | 数据增广方式 | Test top-1 |
|:--:|:--:|:--:|
| ResNet50 | 标准变换 | 77.31% |
| ResNet50 | Auto-Augment | 77.95% |
| ResNet50 | Mixup | 78.28% |
| ResNet50 | Cutmix | 78.39% |
| ResNet50 | Cutout | 78.01% |
| ResNet50 | Gridmask | 77.85% |
| ResNet50 | Random-Augment | 77.70% |
| ResNet50 | Random-Erasing | 77.91% |
| ResNet50 | Hide-and-Seek | 77.43% |
- 其他数据集默认加载ImageNet-1k预训练在其他数据集中除了使用Auto-Augment一般都会有精度的提升Auto-Augment会针对每一个数据集搜索的独立超参数该超参数决定了数据如何处理所以默认的ImageNet-1k的超参数并不适合所有的数据集当然您可以使用Random-Augment来替代Auto-Augment。其他策略可以正常使用对于比较难的任务或者比较小的网络建议不要使用较强的数据增广。
此外,多种数据增广也可以叠加使用,当数据集较为简单或数据规模较小时,叠加数据增广可以进一步提升精度。
### Q5.8 如何通过train_acc和test_acc确定调优策略
**A**:在训练网络的过程中通常会打印每一个epoch的训练集准确率和验证集准确率二者刻画了该模型在两个数据集上的表现。通常来说训练集的准确率反映了经过Random-Crop后的数据的精度由于数据经过Random-Crop后数据往往较难所以训练集的准确率和验证集的准确率往往不是一个概念。
- ImageNet-1k通常来说训练集准确率比验证集准确率微高或者二者相当是比较不错的状态。如果发现训练集的准确率比验证集高很多说明在这个任务上已经过拟合需要在训练过程中加入更多的正则如增大L2Decay的值加入更多的数据增广策略加入label_smoothing策略等如果发现训练集的准确率比验证集低一些说明在这个任务上可能欠拟合需要在训练过程中减弱正则效果如减小L2Decay的值减少数据增广方式增大图片crop区域面积减弱图片拉伸变换去除label_smoothing等。
- 其他数据集默认加载ImageNet-1k预训练基本和训练ImageNet-1k的调整策略相当此外在其他数据集上如果模型趋向于过拟合train acc远大于test acc状态也可以使用更优的预训练权重PaddleClas为常用的网络提供了SSLD的蒸馏预训练权重其比ImageNet-1k的权重更优您可以优先选择。
- **【备注】** 不太建议根据loss来重新调整训练策略在使用不同的数据增广后train loss的大小差异较大如使用Cutmix或者RandAugment后train loss会大于test loss当数据增广策略减弱后train loss会小于test loss所以较难调整。
### Q5.9 如何通过预训练模型提升自己的数据集的精度?
**A**:在现阶段图像识别领域中加载预训练模型来训练自己的任务已成为普遍的做法相比从随机初始化开始训练加载预训练模型往往可以提升特定任务的精度。一般来说业界广泛使用的预训练模型是通过训练128万张图片1000类的ImageNet-1k数据集得到的该预训练模型的fc层权重是是一个k\*1000的矩阵其中k是fc层以前的神经元数在加载预训练权重时无需加载fc层的权重。在学习率方面如果您的任务训练的数据集特别小如小于1千张我们建议你使用较小的初始学习率如0.001batch_size:256,下同以免较大的学习率破坏预训练权重。如果您的训练数据集规模相对较大大于10万我们建议你尝试更大的初始学习率如0.01或者更大。如果目标数据集较小,也可以冻结一些浅层的权重。此外,如果训练一个特定垂类的小数据集,也可以先在相关的大的数据集上训练一个预训练权重,再在该权重上用较小的学习率微调模型。
### Q5.10 现有的策略已经让模型的精度趋于饱和,如何进一步提升特定模型的精度?
**A**:如果现有的策略不能进一步提升模型的精度,说明在现有数据集和现有的策略下,模型几乎到达饱和状态,这里提供两种进一步提升模型精度的方法。
- 挖掘相关数据用在现有数据集上训练饱和的模型去对相关的数据做预测将置信度较高的数据打label后加入训练集进一步训练如此循环操作可进一步提升模型的精度。
- 知识蒸馏可以先使用一个较大的模型在该数据集上训练一个精度较高的teacher model然后使用该teacher model去教导一个Student model其中Student model即为目标模型。PaddleClas提供了百度自研的SSLD知识蒸馏方案即使在ImageNet-1k这么有挑战的分类任务上其也能稳定提升3%以上。SSLD知识蒸馏的的章节请参考[**SSLD知识蒸馏**](../advanced_tutorials/distillation/distillation.md)。
<a name="第6期"></a>
## 第6期
### Q6.1: PaddleClas的几个分支有什么区别应该如何选择
**A**: PaddleClas目前共有3种分支
* 动态图分支dygraph分支是PaddleClas的默认分支也是更新最快的分支。所有的新功能、新改动都会先在dygraph分支上进行。如果想追踪PaddleClas的最新进展可以关注这个分支。这个分支主要支持动态图会跟着paddlepaddle的版本一起更新。
* 稳定版本分支快速更新能够让关注者了解最新进展但也会带来不稳定性。因此在一些关键的时间点我们会从dygraph分支中拉出分支提供稳定的版本。这些分支的名字与paddlepaddle的版本对应如 2.0-beta 为支持paddlepaddle2.0-beta的稳定版本。这些分支一般只会修复bug而不更新新的特性和模型。
* 静态图分支master分支是使用静态图版本的分支主要用来支持一些老用户的使用也只进行一些简单维护不会更新新的特性和模型。不建议新用户使用静态图分支。老用户如果有条件也建议迁到动态图分支或稳定版本分支。
总的来说如果想跟进PaddleClas的最新进展建议选择dygraph分支如果需要稳定版本建议选择最新的稳定版本分支。
### Q6.2: 什么是静态图模式?
**A**: 静态图模式即为声明式编程模式。许多深度学习框架如tensorflowmxnet等最初都使用这种模式。在静态图模式中需要先定义好模型结构之后框架会根据模型结构进行编译和优化构建"计算图"。可以简单的理解为,静态图模式是"计算图"静态不变的模式。静态图的优势在于编译器一般只需要构建一次计算图效率相对较高缺点在于不够灵活调试麻烦。例如在paddle中运行一次静态图模型需要完整所有的运算之后根据特定的key来提取输出无法实时得到结果。
### Q6.3: 什么是动态图模式?
**A**: 动态图模式即为命令式编程模式,用户无需预先定义网络结构,每行代码都可以直接运行得到结果。相比静态图模式,动态图模式对用户更加友好,调试也更方便。此外,动态图模式的结构设计也更加灵活,可以在运行过程中随时调整结构。
PaddleClas目前持续更新的dygraph分支主要采用动态图模式。如果您是新用户建议使用动态图模式来进行开发和训练。如果推理预测时有性能需求可以在训练完成后将动态图模型转为静态图模型提高效率。
### Q6.4: 动态图模型的预测效率有时不如静态图,应该怎么办?
**A**: 可以使用转换工具将动态图模型转换为静态图模型具体可以参考https://www.paddlepaddle.org.cn/documentation/docs/zh/2.0-rc1/guides/04_dygraph_to_static/index_cn.html。
### Q6.5: 构建分类数据集时,如何构建"背景"类别的数据?
**A**: 实际使用中,常常需要自己构建一个分类数据集来进行训练。除了所需要的类别数据之外,还需要一个额外的类别,即"背景"类别。例如做一个猫狗分类,猫为一类,狗为一类,如果我们的分类器只有两类,那么输入一张兔子的图片,也会被强制的分到这两个类别中的一个。因此在训练时,应添加一些非目标类别的数据,作为"背景"类别的数据。
构建"背景"类别的数据时,首先应从实际需求的角度出发。还是以猫狗分类器为例,如果实际测试的数据都是动物,那么"背景"类别的数据就应该包含一些除猫狗之外的动物。而如果测试的数据还包含更多类别,例如一棵树,那么"背景"类别的数据就要设置的更加丰富。
简单来说,"背景"类别的数据,要根据实际场景中可能出现的情况去收集。情况越多,需要涵盖的数据种类就越多,任务也会相应的越困难。因此实际处理中,最好能对问题进行限制,避免浪费资源和算力。

View File

@ -0,0 +1,267 @@
# 图像分类常见问题汇总 - 2021 第1季
## 目录
* [第1期](#第1期)(2021.01.05)
* [第2期](#第2期)(2021.01.14)
* [第3期](#第3期)(2020.01.21)
* [第4期](#第4期)(2021.01.28)
* [第5期](#第5期)(2021.02.03)
<a name="第1期"></a>
## 第1期
### Q1.1: 在模型导出时发现导出的inference model预测精度很低这块是为什么呢
**A**:可以从以下几个方面排查
* 需要先排查下预训练模型路径是否正确。
* 模型导出时默认的类别数为1000如果预训练模型是自定义的类别数则在导出的时候需要指定参数`--class_num=k`k是自定义的类别数。
* 可以对比下`tools/infer/infer.py`和`tools/infer/predict.py`针对相同输入的输出class id与score如果完全相同则可能是预训练模型自身的精度很差。
### Q1.2: 训练样本的类别不均衡,这个该怎么处理呢?
**A**:有以下几种比较常用的处理方法。
* 从采样的角度出发的话
* 可以对样本根据类别进行动态采样每个类别都设置不同的采样概率保证不同类别的图片在同一个minibatch或者同一个epoch内不同类别的训练样本数量基本一致或者符合自己期望的比例。
* 可以使用过采样的方法,对图片数量较少的类别进行过采样。
* 从损失函数的角度出发的话
* 可以使用OHEM(online hard example miniing)的方法对根据样本的loss进行筛选筛选出hard example用于模型的梯度反传和参数更新。
* 可以使用Focal loss的方法对一些比较容易的样本的loss赋予较小的权重对于难样本的loss赋予较大的权重从而让容易样本的loss对网络整体的loss有贡献但是又不会主导loss。
### Q1.3 在docker中训练的时候数据路径和配置均没问题但是一直报错`SystemError: (Fatal) Blocking queue is killed because the data reader raises an exception`,这是为什么呢?
**A**这可能是因为docker中共享内存太小导致的。创建docker的时候`/dev/shm`的默认大小为64M如果使用多进程读取数据共享内存可能不够因此需要给`/dev/shm`分配更大的空间在创建docker的时候传入`--shm-size=8g`表示给`/dev/shm`分配8g的空间一般是够用的。
### Q1.4 PaddleClas提供的10W类图像分类预训练模型在哪里下载应该怎么使用呢
**A**基于ResNet50_vd, 百度开源了自研的大规模分类预训练模型其中训练数据为10万个类别4300万张图片。10万类预训练模型的下载地址[下载地址](https://paddle-imagenet-models-name.bj.bcebos.com/ResNet50_vd_10w_pretrained.tar)在这里需要注意的是该预训练模型没有提供最后的FC层参数因此无法直接拿来预测但是可以使用它作为预训练模型在自己的数据集上进行微调。经过验证该预训练模型相比于基于ImageNet1k数据集的ResNet50_vd预训练模型在不同的数据集上均有比较明显的精度收益最多可达30%,更多的对比实验可以参考:[图像分类迁移学习教程](../application/transfer_learning.md)。
### Q1.5 使用C++进行预测部署的时候怎么进行加速呢?
**A**:可以从以下几个方面加速预测过程。
1. 如果是CPU预测的话可以开启mkldnn进行预测同时适当增大运算的线程数(cpu_math_library_num_threads在`tools/config.txt`中)一般设置为6~10比较有效。
2. 如果是GPU预测的话在硬件条件允许的情况下可以开启TensorRT预测以及FP16预测这可以进一步加快预测速度。
3. 在内存或者显存足够的情况下可以增大预测的batch size。
4. 可以将图像预处理的逻辑(主要设计resize、crop、normalize等)放在GPU上运行这可以进一步加速预测过程。
更多的预测部署加速技巧,也欢迎大家补充。
<a name="第2期"></a>
## 第2期
### Q2.1: PaddleClas在设置标签的时候必须从0开始吗class_num必须等于数据集的类别数吗
**A**在PaddleClas中标签默认是从0开始所以尽量从0开始设置标签当然从其他值开始设置也可以这样会导致设置的class_num增大进而导致分类的FC层参数量较大权重文件会占用更多的存储空间。在数据集类别连续的情况下设置的class_num要等于数据集类别数当然大于数据集类别数也可以在很多数据集上甚至可以获得更高的精度但同样会使FC层参数量较大在数据集类别数不连续的情况下设置的class_num要等于数据集中最大的class_id+1。
### Q2.2: 当类别数特别多的时候最后的FC特别大导致权重文件占用较大的存储空间该怎么解决
**A**最终的FC的权重是一个大的矩阵大小为C*class_num其中C为FC前一层的神经单元个数如ResNet50中的C为2048可以通过降低C的值来进一步减小FC权重的大小比如可以在GAP之后加一层维数较小的FC层这样可以大大缩小最终分类层的权重大小。
### Q2.3: 为什么使用PaddleClas在自定义的数据集上训练ssld蒸馏没有达到预期
首先需要确保Teacher模型的精度是否存在问题其次需要确保Student模型是否成功加载了ImageNet-1k的预训练权重以及Teacher模型是否成功加载了训练自定义数据集的权重最后要确保初次学习率不应太大至少保证初始学习率不要超过训练ImageNet-1k的值。
### Q2.4: 移动端或嵌入式端上哪些网络具有优势?
建议使用移动端系列的网络,网络详情可以参考[移动端系列网络结构介绍](../models/Mobile.md)。如果任务的速度更重要可以考虑MobileNetV3系列如果模型大小更重要可以根据移动端系列网络结构介绍中的StorageSize-Accuracy来确定具体的结构。
### Q2.5: 既然移动端网络非常快为什么还要使用诸如ResNet这样参数量和计算量较大的网络
不同的网络结构在不同的设备上运行速度优势不同。在移动端移动端系列的网络比服务器端的网络运行速度更快但是在服务器端相同精度下ResNet等经过特定优化后的网络具有更大的优势所以需要根据具体情况来选择具体的网络结构。
<a name="第3期"></a>
## 第3期
### Q3.1: 双分支结构与Plain结构各自有什么特点
**A**
以VGG为代表的Plain网络发展到以ResNet系列带有残差模块、Inception系列多卷积核并行为代表的的多分支网络结构人们发现多分支结构在模型训练阶段更为友好更大的网络宽度可以带来更强的特征拟合能力而残差结构则可以避免深度网络梯度消失的问题但是在推理阶段带有多分支结构的模型在速度上并无优势即使多分支结构模型的FLOPs要更低但多分支结构的模型计算密度也更低。例如VGG16模型的FLOPs远远大于EfficientNetB3但是VGG16模型的推理速度却显著快于EfficientNetB3因此多分支结构在模型训练阶段更为友好而Plain结构模型则更适合于推理阶段那么以此为出发点可以在训练阶段使用多分支网络结构以更大的训练时间成本换取特征拟合能力更强的模型而在推理阶段将多分支结构转为Plain结构从而换取更短的推理时间。实现多分支结构到Plain结构的转换可以通过结构重参数化structural re-parameterization技术实现。
另外Plain结构对于剪枝操作也更为友好。
“Plain结构”与“结构重参数化structural re-parameterization技术”出自论文“RepVGG: Making VGG-style ConvNets Great Again”。Plain结构网络模型指整个网络不存在分支结构也即网络中第`i`层layer的输入为第`i-1`层layer的输出第`i`层layer的输出为第`i+1`层layer的输入。
### Q3.2: ACNet的创新点主要在哪里
**A**
ACNet意为“Asymmetric Convolution Block”即为非对称卷积模块该思想出自论文“ACNet: Strengthening the Kernel Skeletons for Powerful CNN via Asymmetric Convolution Blocks”文章提出了以“ACB”结构的三个CNN卷积核为一组用来在训练阶段替代现有卷积神经网络中的传统方形卷积核。
方形卷积核的尺寸为假设为`d*d`,即宽、高相等均为`d`则用于替换该卷积核的ACB结构是尺寸为`d*d`、`1*d`、`d*1`的三个卷积核,然后再将三个卷积核的输出直接相加,可以得到与原有方形卷积核相同尺寸的计算结果。
而在训练完成后将ACB结构换回原有的方形卷积核方形卷积核的参数则为ACB结构的三个卷积核的参数直接相加见`Q3.4`因此还是使用与之前相同的模型结构用于推理ACB结构只是在训练阶段使用。
在训练中通过ACB结构模型的网络宽度得到了提高利用`1*d`、`d*1`的两个非对称卷积核提取得到更多的特征用于丰富`d*d`卷积核提取的特征图的信息。而在推理阶段,这种设计思想并没有带来额外的参数与计算开销。如下图所示,分别是用于训练阶段和部署推理阶段的卷积核形式。
<div align="center">
<img src="../../images/faq/TrainingtimeACNet.png" width="400">
</div>
<div align="center">
<img src="../../images/faq/DeployedACNet.png" width="400">
</div>
文章作者的实验表明通过在原有网络模型训练中使用ACNet结构可以显著提高模型能力原作者对此有如下解释
1. 实验表明,对于一个`d*d`的卷积核,相对于消除卷积核角落位置(如上图中卷积核的`corners`位置)的参数而言,消除骨架位置(如上图中卷积核的`skeleton`位置的参数会给模型精度带来更大的影响因此卷积核骨架位置的参数要更为重要而ACB结构中的两个非对称卷积核增强了方形卷积核骨架位置参数的权重使之作用更为显著。这种相加是否会因正负数抵消作用而减弱骨架位置的参数作用作者通过实验发现网络的训练总是会向着提高骨架位置参数作用的方向发展并没有出现正负数抵消而减弱的现象。
2. 非对称卷积核对于翻转的图像具有更强的鲁棒性,如下图所示,水平的非对称卷积核对于上下翻转的图像具有更强的鲁棒性。对于翻转前后图像中语义上的同一位置,非对称卷积核提取的特征图是相同的,这一点要强于方形卷积核。
<div align="center">
<img src="../../images/faq/HorizontalKernel.png" width="400">
</div>
### Q3.3: RepVGG的创新点主要在哪里
**A**
通过Q3.1与Q3.2我们可以大胆想到是否可以借鉴ACNet将训练阶段与推理阶段解耦并且训练阶段使用多分支结构推理阶段使用Plain结构这也就是RepVGG的创新点。下图为ResNet、RepVGG训练和推理阶段网络结构的对比。
<div align="center">
<img src="../../images/faq/RepVGG.png" width="400">
</div>
首先训练阶段的RepVGG采用多分支结构可以看作是在传统VGG网络的基础上增加了`1*1`卷积和恒等映射的残差结构而推理阶段的RepVGG则退化为VGG结构。训练阶段RepVGG到推理阶段RepVGG的网络结构转换使用“结构重参数化”技术实现。
对于恒等映射,可将其视为参数均为`1`的`1*1`卷积核作用在输入特征图的输出结果因此训练阶段的RepVGG的卷积模块可以视为两个`1*1`卷积和一个`3*3`卷积,而`1*1`卷积的参数又可以直接相加到`3*3`卷积核中心位置的参数上该操作类似于ACNet中非对称卷积核参数相加到方形卷积核骨架位置参数的操作通过上述操作即可在推理阶段将网络结构中的恒等映射、`1*1`卷积、`3*3`卷积三个分支合并为一个`3*3`卷积,详见`Q3.4`。
### Q3.4: ACNet与RepVGG中的struct re-parameters有何异同
**A**
通过上面的了解可以简单理解RepVGG是更为极端的ACNet。ACNet中的re-parameters操作如下图所示
<div align="center">
<img src="../../images/faq/ACNetReParams.png" width="400">
</div>
观察上图,以其中的`conv2`为例,该非对称卷积可以视为`3*3`的方形卷积核,只不过该方形卷积核的上下六个参数为`0``conv3`同理。并且,`conv1`、`conv2`、`conv3`的结果相加,等同于三个卷积核相加再做卷积,以`Conv`表示卷积操作,`+`表示矩阵的加法操作,则:`Conv1(A)+Conv2(A)+Conv3(A) == Convk(A)`,其中`Conv1`、`Conv2`、`Conv3`的卷积核分别为`Kernel1`、`kernel2`、`kernel3`,而`Convk`的卷积核为`Kernel1 + kernel2 + kernel3`。
RepVGG网络与ACNet同理只不过ACNet的`1*d`非对称卷积变成了`1*1`卷积,`1*1`卷积相加的位置变成了`3*3`卷积的中心。
### Q3.5: 影响模型计算速度的因素都有哪些?参数量越大的模型计算速度一定更慢吗?
**A**
影响模型计算速度的因素有很多,参数量只是其中之一。具体来说,在不考虑硬件差异的前提下,模型的计算速度可以参考以下几个方面:
1. 参数量:用于衡量模型的参数数量,模型的参数量越大,模型在计算时对内存(显存)的容量要求一般也更高。但内存(显存)占用大小不完全取决于参数量。如下图中,假设输入特征图内存占用大小为`1`个单位对于左侧的残差结构而言由于需要记录两个分支的运算结果然后再相加因此该结构在计算时的内存峰值占用是右侧Plain结构的两倍。
<div align="center">
<img src="../../images/faq/MemoryOccupation.png" width="400">
</div>
2. 浮点运算数量FLOPs注意与每秒浮点运算次数FLOPS相区分。FLOPs可以简单理解为计算量通常用来衡量一个模型的计算复杂度。
以常见的卷积操作为例在不考虑batch size、激活函数、stride操作、bias的前提下假设input future map尺寸为`Min*Min`,通道数为`Cin`output future map尺寸为`Mout*Mout`,通道数为`Cout`conv kernel尺寸为`K*K`则进行一次卷积的FLOPs可以通过下述方式计算
1. 输出特征图包含特征点的数量为:`Cout * Mout * Mout`
2. 对于输出特征图中的每一个特征点的卷积操作而言:
乘法计算数量为:`Cin * K * K`
加法计算数量为:`Cin * K * K - 1`
3. 因此计算总量为:`Cout * Mout * Mout * (Cin * K * K + Cin * K * K - 1)`,也即`Cout * Mout * Mout * (2Cin * K * K - 1)`。
3. Memory Access CostMAC内存访问成本由于计算机在对数据进行运算例如乘法、加法需要将运算的数据从内存此处泛指内存包括显存读取到运算器的Cache中而内存的访问是十分耗时的。以分组卷积为例假设分为`g`组虽然分组后模型的参数量和FLOPs没有变化但是分组卷积的内存访问次数成为之前的`g`倍此处只是简单计算未考虑多级Cache因此MAC显著提高模型的计算速度也相应变慢。
4. 并行度常说的并行度包括数据并行和模型并行两部分此处是指模型并行。以卷积操作为例一个卷积层的参数量通常十分庞大如果将卷积层中的矩阵做分块处理然后分别交由多个GPU进行运算即可达到加速的目的。甚至有的网络层参数量过大单张GPU显存无法容纳时也可能将该层分由多个GPU计算但是能否分由多个GPU并行运算不仅取决于硬件条件也受特定的运算形式所限制。当然并行度越高的模型其运行速度也越快。
<a name="第4期"></a>
## 第4期
### Q4.1: 图像分类任务中,有一部分合成数据,这一部分合成数据是否需要使用样本均衡?
**A**:
1. 不同类别的样本数如果差异过大,某类样本因合成数据集扩充至其他类的数倍以上,需要做适当减小该类的权值。
2. 如果是有的类别是合成而有的类别半合成半真实,只要数量在一个量级可不做均衡,并尝试训练一下,测试该合成类别样本是否能够准确识别。
3. 如果不同来源数据的类别因合成数据增大问题,造成性能衰减,需要考虑合成数据集是否有噪声或者难例样本,也可适当增加该类别权重,获得该类别更好的识别性能。
### Q4.2: 学术界将Vision Transformer(ViT)引入图像分类领域将对图像分类带来什么新的机遇和挑战相比于CNN的优势
论文地址[AN IMAGE IS WORTH 16X16 WORDS: TRANSFORMERS FOR IMAGE RECOGNITION AT SCALE](https://openreview.net/pdf?id=YicbFdNTTy)
**A**:
1. 图像对CNN的依赖是不必要的利用Transformer的计算效率和可伸缩性可以训练很大模型当模型和数据集增大的情形下仍然不会存在饱和的情况。受到Transformer在NLP上的启发在图像分类任务中使用时将图片分成顺序排列的patches并将这些patches输入一个线性单元嵌入到embedding作为transformer的输入。
2. 在中等规模数据集中如ImageNetImageNet21k视觉Transformer模型低于相同规模尺寸的ResNet几个百分点。这是因为transformer缺少CNN平移和局限性在数据量不够大的时候不能超越卷积网络。
3. 在超大规模数据集14M-300M训练时这种方式可以越过局部信息建模更加长距离的依赖关系而CNN能较好关注局部信息全局信息捕获能力较弱。
4. Transformer一度在NLP领域一统江湖也一度被质疑不适用于CV领域当前出来的几片视觉领域的文章性能也是直逼CNN的SOTA。相信在未来能够提出Vision-Language联合或者多模态的模型能够一并解决视觉和语言问题。
### Q4.3: 对于Vision Transformer模型是如何将图像转换成序列信息传给Encoder
**A**:
1. 使用Transformer模型主要是使用其中的注意力方法。我们希望构想一个适用语义embedding信息的场景但是图像分类与序列的语义信息关联性不大因此Vision Transformer有其独特的设计。ViT的目标也正是希望使用注意力机制来代替CNN。
2. 考虑Transformer中Encoder编码器的输入形式如下图:
* (1)不定长度的顺序输入因为它是RNN结构一句话单词数不一样。如果是NLP场景换词的顺序不太过于影响语义但是图像换了不同区域的位置不同区域连接顺序不同将造成极大理解偏差。
* (2)单个patch位置信息通过变换成一个维度固定的向量Encoder输入是patch像素信息embedding与一些固定位置的向量concate 合成一个维度固定的向量和位置信息在其中。
<div align="center">
<img src="../../images/faq/Transformer_input.png" width="400">
</div>
3. 考虑以下问题怎样将一张图片怎么传给encoder
* 如下图所示。假设输入图片是[224,224,3]按照顺序从左到右从上到下切分成很多个patchpatch大小可以为[p,p,3]p取值可以是1632对其使用Linear Projection of Flattened Patches模块转成特征向量并concat一个位置向量传入Encoder中。
<div align="center">
<img src="../../images/faq/ViT_structure.png" width="400">
</div>
4. 如上图,给定一个`H×W×C`的图像以及区块大小P可以把图像划分为`N`个`P×P×C`的区块,`N=H×W/(P×P)`。得到区块后要使用线性变换转为D维特征向量再加上位置编码向量即可。和BERT类似ViT 在序列之前也加入了一个分类标志位,记为`[CLS]`。ViT输入序列`z`如下面的公式所示,其中`x`表示一个图像区块。
<div align="center">
<img src="../../images/faq/ViT.png" width="400">
</div>
5. ViT 模型和 Transformer 基本一样,输入序列传入 ViT然后利用`[CLS]`标志位的最终输出特征进行分类。ViT主要由MSA(多头自注意力)和MLP(两层使用GELU激活函数的全连接网络) 组成在MSA和MLP之前加上LayerNorm和残差连接。
### Q4.4: 如何理解归纳偏置Inductive Bias
**A**:
1. 在机器学习中会对算需要应用的问题做一些假设这个假设就称为归纳偏好。在现实生活中观察得到的现象中归纳出一定的先验规则然后对模型做一定的约束从而起到模型选择的作用。在CNN中假设特征具有局部性(Locality)和空间不变性(Spatial Invariance)的特点即把相邻的的特征有联系而远离的没有将相邻特征融合在一起更会容易产生“解”还有attention机制也是从人的直觉、生活经验归纳的规则。
2. Vision Transformer利用的归纳偏置是有序列能力Sequentiality和时间不变性Time Invariance即序列顺序上的时间间隔的联系因此也能得出在更大规模数据集上比CNN类的模型有更好的性能。文章Conclusion里的“Unlike prior works using self-attention in computer vision, we do not introduce any image-specific inductive biases into the architecture”和Introduction里的“We find that large scale training trumps inductive bias”可以得出直观上inductive bias在大量数据的情况中的产生是衰减性能应该尽可能丢弃。
### Q4.5: ViT为什么要增加一个[CLS]标志位? 为什么将[CLS]标志位对应的向量作为整个序列的语义表示?
**A**:
1. 和BERT相类似ViT在第一个patch前添加一个`[CLS]`标志位最后一个结束标志位对应的向量可以作为整个图像的语义表示从而用于下游的分类任务等。从而使得整个embedding组可以表征该图像不同位置的特征。
2. 将`[CLS]`标志位对应的向量作为整个图像的语义表示是因为与图像中已有的其它patch块图像相比这个无明显语义信息的符号会更“公平”地融合图像中各个patch的语义信息从而更好的表示整个图像的语义。
<a name="第5期"></a>
## 第5期
### Q5.1: PaddleClas训练配置文件中都包含了哪些内容训练模型时如何进行修改
**A**:
PaddleClas的模型包含6大模块的配置分别为全局配置网络结构(ARCHITECTURE),学习率(LEARNING_RATE),优化器(OPTIMIZER),训练(TRAIN)和验证(VALID)。
全局配置主要包含了任务的配置信息例如类别的数量训练集内的数据量训练的epoch数量网络输入的尺寸等等。如果要训练自定义的任务或是使用自己的训练集需要关注这个部分。
网络结构的配置定义了要使用的网络。在实际使用时,首先要选择合适的配置文件,所以通常不会修改这部分配置。只有在自定义网络结构,或者对任务有特殊要求时才进行修改。
学习率和优化器的配置建议优先使用默认配置,这些参数是我们已经调过的。如果任务的改动比较大,也可以做微调。
训练和预测两个配置包含了batch_size数据集数据预处理transforms读数据进程数num_workers等比较重要的配置这部分要根据实际环境适度修改。要注意的是paddleclas中的batch_size是全局的配置即不随卡数发生变化。而num_workers定义的是单卡的进程数即如果num_workers是8并且使用4卡训练则实际有32个worker。
### Q5.2: 如何在命令行中快速的修改配置?
**A**:
在训练中,我们常常需要对个别配置不断进行微调,而不希望频繁的修改配置文件。这时可以使用-o来调整修改是要先按层级写出要改的配置名称层级之间用点分割再写出要修改的值。例如我们想要修改batch_size可以在训练的命令后加上-o TRAIN.batchsize=512。
### Q5.3: 如何根据PaddleClas的精度曲线选择合适的模型
**A**:
PaddleClas提供了多个模型的benchmark并绘制了性能曲线主要有三种准确率-预测时间曲线,准确率-参数量曲线和准确率-FLOPS曲线纵轴为准确率横轴分别为预测时间、参数量、FLOPS。一般来说不同模型在三个图上的表现是一致的。同一个系列的模型在图上采用相同的符号来表示并且用曲线连接。
以准确率-预测时间曲线为例点越靠上表明准确率越高约靠左表明速度越快。例如左上区域的模型为又快又准的模型而最左侧贴近纵轴的点则为轻量级的模型。使用时可以综合考虑准确率和时间因素选择合适的模型。举个例子我们希望模型的运行时间在10ms以下选择最准确的模型。首先在横轴的10ms出画一条垂直的线之后在这条线的左侧找到最高的点就是符合要求的模型。
实际使用中模型的参数量和FLOPS是稳定不变的而运算时间在不同的软硬件条件下均会有所变化。如果想更准确的选择模型那么可以在自己的环境中运行测试得到该环境下的性能图。
### Q5.4: 想在imagenet中增加两个类能不能把现有全连接层的参数固定只训练新的两个类别
**A**:
这个想法理论上可行,但效果恐怕不会太好。如果只是固定全连接层,而前面的卷积层参数发生了变化,那么这些全连接层的作用也无法保证与开始一样。而如果保持整个网络的参数都不变,只训练全连接层的新增两个类别,也比较难训练处理想的结果。
如果实际使用中确实需要原有的1000个类别依然很准确那么可以将新类别的数据加入到原有训练集中再用预训练模型进行finetune。如果只需要1000个类中的几个类别那么可以把这部分的数据挑出来和新增数据混合再finetune。
### Q5.5: 使用分类模型做其他任务的预训练模型时应该选择哪些层作为feature
**A**:
使用分类模型做其他任务的backbone有很多策略这里介绍一种较为基础的方法。首先去掉最后的全连接层这一层主要包含的是原始任务的分类信息。如果任务比较简单只要将前一层的输出作为featuremap并在此基础上添加与任务对应的结构即可。如果任务涉及多尺度需要选取不同尺度的anchor例如某些检测模型那么可以选取每次下采样之前一层的输出作为featuremap。

View File

@ -0,0 +1,342 @@
# PaddleClas 相关常见问题汇总 - 2021 第2季
## 写在前面
* 我们收集整理了开源以来在issues和用户群中的常见问题并且给出了简要解答旨在为广大用户提供一些参考也希望帮助大家少走一些弯路。
* 图像分类、识别、检索领域大佬众多,模型和论文更新速度也很快,本文档回答主要依赖有限的项目实践,难免挂一漏万,如有遗漏和不足,也希望有识之士帮忙补充和修正,万分感谢。
## 目录
* [近期更新](#近期更新)(2021.09.08)
* [精选](#精选)
* [1. 理论篇](#1.理论篇)
* [1.1 PaddleClas基础知识](#1.1PaddleClas基础知识)
* [1.2 骨干网络和预训练模型库](#1.2骨干网络和预训练模型库)
* [1.3 图像分类](#1.3图像分类)
* [1.4 通用检测模块](#1.4通用检测模块)
* [1.5 图像识别模块](#1.5图像识别模块)
* [1.6 检索模块](#1.6检索模块)
* [2. 实战篇](#2.实战篇)
* [2.1 训练与评估共性问题](#2.1训练与评估共性问题)
* [2.2 图像分类](#2.2图像分类)
* [2.3 通用检测模块](#2.3通用检测模块)
* [2.4 图像识别模块](#2.4图像识别模块)
* [2.5 检索模块](#2.5检索模块)
* [2.6 模型预测部署](#2.6模型预测部署)
<a name="近期更新"></a>
## 近期更新
#### Q2.1.7: 在训练时,出现如下报错信息:`ERROR: Unexpected segmentation fault encountered in DataLoader workers.`,如何排查解决问题呢?
**A**:尝试将训练配置文件中的字段 `num_workers` 设置为 `0`;尝试将训练配置文件中的字段 `batch_size` 调小一些;检查数据集格式和配置文件中的数据集路径是否正确。
#### Q2.1.8: 如何在训练时使用 `Mixup``Cutmix`
**A**
* `Mixup` 的使用方法请参考 [Mixup](https://github.com/PaddlePaddle/PaddleClas/blob/cf9fc9363877f919996954a63716acfb959619d0/ppcls/configs/ImageNet/DataAugment/ResNet50_Mixup.yaml#L63-L65)`Cuxmix` 请参考 [Cuxmix](https://github.com/PaddlePaddle/PaddleClas/blob/cf9fc9363877f919996954a63716acfb959619d0/ppcls/configs/ImageNet/DataAugment/ResNet50_Cutmix.yaml#L63-L65)。
* 在使用 `Mixup``Cutmix` 时,需要注意:
* 配置文件中的 `Loss.Tranin.CELoss` 需要修改为 `Loss.Tranin.MixCELoss`,可参考 [MixCELoss](https://github.com/PaddlePaddle/PaddleClas/blob/cf9fc9363877f919996954a63716acfb959619d0/ppcls/configs/ImageNet/DataAugment/ResNet50_Cutmix.yaml#L23-L26)
* 使用 `Mixup``Cutmix` 做训练时无法计算训练的精度Acc指标因此需要在配置文件中取消 `Metric.Train.TopkAcc` 字段,可参考 [Metric.Train.TopkAcc](https://github.com/PaddlePaddle/PaddleClas/blob/cf9fc9363877f919996954a63716acfb959619d0/ppcls/configs/ImageNet/DataAugment/ResNet50_Cutmix.yaml#L125-L128)。
#### Q2.1.9: 训练配置yaml文件中字段 `Global.pretrain_model``Global.checkpoints` 分别用于配置什么呢?
**A**
* 当需要 `fine-tune` 时,可以通过字段 `Global.pretrain_model` 配置预训练模型权重文件的路径,预训练模型权重文件后缀名通常为 `.pdparams`
* 在训练过程中训练程序会自动保存每个epoch结束时的断点信息包括优化器信息 `.pdopt` 和模型权重信息 `.pdparams`。在训练过程意外中断等情况下,需要恢复训练时,可以通过字段 `Global.checkpoints` 配置训练过程中保存的断点信息文件,例如通过配置 `checkpoints: ./output/ResNet18/epoch_18` 即可恢复18epoch训练结束时的断点信息PaddleClas将自动加载 `epoch_18.pdopt``epoch_18.pdparams`从19epoch继续训练。
#### Q2.6.3: 如何将模型转为 `ONNX` 格式?
**A**Paddle支持两种转ONNX格式模型的方式且依赖于 `paddle2onnx` 工具,首先需要安装 `paddle2onnx`
```shell
pip install paddle2onnx
```
* 从 inference model 转为 ONNX 格式模型:
以动态图导出的 `combined` 格式 inference model包含 `.pdmodel``.pdiparams` 两个文件)为例,使用以下命令进行模型格式转换:
```shell
paddle2onnx --model_dir ${model_path} --model_filename ${model_path}/inference.pdmodel --params_filename ${model_path}/inference.pdiparams --save_file ${save_path}/model.onnx --enable_onnx_checker True
```
上述命令中:
* `model_dir`:该参数下需要包含 `.pdmodel``.pdiparams` 两个文件;
* `model_filename`:该参数用于指定参数 `model_dir` 下的 `.pdmodel` 文件路径;
* `params_filename`:该参数用于指定参数 `model_dir` 下的 `.pdiparams` 文件路径;
* `save_file`:该参数用于指定转换后的模型保存目录路径。
关于静态图导出的非 `combined` 格式的 inference model通常包含文件 `__model__` 和多个参数文件)转换模型格式,以及更多参数说明请参考 paddle2onnx 官方文档 [paddle2onnx](https://github.com/PaddlePaddle/Paddle2ONNX/blob/develop/README_zh.md#%E5%8F%82%E6%95%B0%E9%80%89%E9%A1%B9)。
* 直接从模型组网代码导出ONNX格式模型
以动态图模型组网代码为例,模型类为继承于 `paddle.nn.Layer` 的子类,代码如下所示:
```python
import paddle
from paddle.static import InputSpec
class SimpleNet(paddle.nn.Layer):
def __init__(self):
pass
def forward(self, x):
pass
net = SimpleNet()
x_spec = InputSpec(shape=[None, 3, 224, 224], dtype='float32', name='x')
paddle.onnx.export(layer=net, path="./SimpleNet", input_spec=[x_spec])
```
其中:
* `InputSpec()` 函数用于描述模型输入的签名信息,包括输入数据的 `shape`、`type` 和 `name`(可省略);
* `paddle.onnx.export()` 函数需要指定模型组网对象 `net`,导出模型的保存路径 `save_path`,模型的输入数据描述 `input_spec`
需要注意,`paddlepaddle` 版本需大于 `2.0.0`。关于 `paddle.onnx.export()` 函数的更多参数说明请参考[paddle.onnx.export](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/onnx/export_cn.html#export)。
#### Q2.5.4: 在 build 检索底库时,参数 `pq_size` 应该如何设置?
**A**`pq_size` 是PQ检索算法的参数。PQ检索算法可以简单理解为“分层”检索算法`pq_size` 是每层的“容量”因此该参数的设置会影响检索性能不过在底库总数据量不太大小于10000张的情况下这个参数对性能的影响很小因此对于大多数使用场景而言在构建底库时无需修改该参数。关于PQ检索算法的更多内容可以查看相关[论文](https://lear.inrialpes.fr/pubs/2011/JDS11/jegou_searching_with_quantization.pdf)。
<a name="精选"></a>
## 精选
<a name="1.理论篇"></a>
## 1. 理论篇
<a name="1.1PaddleClas基础知识"></a>
### 1.1 PaddleClas基础知识
#### Q1.1.1 PaddleClas和PaddleDetection区别
**A**PaddleClas是一个兼主体检测、图像分类、图像检索于一体的图像识别repo用于解决大部分图像识别问题用户可以很方便的使用PaddleClas来解决小样本、多类别的图像识别问题。PaddleDetection提供了目标检测、关键点检测、多目标跟踪等能力方便用户定位图像中的感兴趣的点和区域被广泛应用于工业质检、遥感图像检测、无人巡检等项目。
#### Q1.1.2 PaddleClas 2.2和PaddleClas 2.1完全兼容吗?
**A**PaddleClas2.2相对PaddleClas2.1新增了metric learning模块主体检测模块、向量检索模块。另外也提供了商品识别、车辆识别、logo识别和动漫人物识别等4个场景应用示例。用户可以基于PaddleClas 2.2快速构建图像识别系统。在图像分类模块,二者的使用方法类似,可以参考[图像分类示例](../tutorials/getting_started.md)快速迭代和评估。新增的metric learning模块可以参考[metric learning示例](../tutorials/getting_started_retrieval.md)。另外新版本暂时还不支持fp16、dali训练也暂时不支持多标签训练这块内容将在不久后支持。
#### Q1.1.3: Momentum 优化器中的 momentum 参数是什么意思呢?
**A**: Momentum 优化器是在 SGD 优化器的基础上引入了“动量”的概念。在 SGD 优化器中,在 `t+1` 时刻,参数 `w` 的更新可表示为:
```latex
w_t+1 = w_t - lr * grad
```
其中,`lr` 为学习率,`grad` 为此时参数 `w` 的梯度。在引入动量的概念后,参数 `w` 的更新可表示为:
```latex
v_t+1 = m * v_t + lr * grad
w_t+1 = w_t - v_t+1
```
其中,`m` 即为动量 `momentum`,表示累积动量的加权值,一般取 `0.9`,当取值小于 `1` 时,则越早期的梯度对当前的影响越小,例如,当动量参数 `m``0.9` 时,在 `t` 时刻,`t-5` 的梯度加权值为 `0.9 ^ 5 = 0.59049`,而 `t-2` 时刻的梯度加权值为 `0.9 ^ 2 = 0.81`。因此,太过“久远”的梯度信息对当前的参考意义很小,而“最近”的历史梯度信息对当前影响更大,这也是符合直觉的。
<div align="center">
<img src="../../images/faq/momentum.jpeg" width="400">
</div>
通过引入动量的概念,在参数更新时考虑了历史更新的影响,因此可以加快收敛速度,也改善了 `SGD` 优化器带来的损失cost、loss震荡问题。
#### Q1.1.4: PaddleClas 是否有 `Fixing the train-test resolution discrepancy` 这篇论文的实现呢?
**A**: 目前 PaddleClas 没有实现。如果需要可以尝试自己修改代码。简单来说该论文所提出的思想是使用较大分辨率作为输入对已经训练好的模型最后的FC层进行fine-tune。具体操作上首先在较低分辨率的数据集上对模型网络进行训练完成训练后对网络除最后的FC层外的其他层的权重设置参数 `stop_gradient=True`然后使用较大分辨率的输入对网络进行fine-tune训练。
<a name="1.2骨干网络和预训练模型库"></a>
### 1.2 骨干网络和预训练模型库
<a name="1.3图像分类"></a>
### 1.3 图像分类
#### Q1.3.1: PaddleClas有提供调整图片亮度对比度饱和度色调等方面的数据增强吗
**A**PaddleClas提供了多种数据增广方式 可分为3类
1. 图像变换类: AutoAugment, RandAugment;
2. 图像裁剪类: CutOut、RandErasing、HideAndSeek、GridMask
3. 图像混叠类Mixup, Cutmix.
其中Randangment提供了多种数据增强方式的随机组合可以满足亮度、对比度、饱和度、色调等多方面的数据增广需求
<a name="1.4通用检测模块"></a>
### 1.4 通用检测模块
#### Q1.4.1 主体检测是每次只输出一个主体检测框吗?
**A**主体检测这块的输出数量是可以通过配置文件配置的。在配置文件中Global.threshold控制检测的阈值小于该阈值的检测框被舍弃Global.max_det_results控制最大返回的结果数这两个参数共同决定了输出检测框的数量。
#### Q1.4.2 训练主体检测模型的数据是如何选择的?换成更小的模型会有损精度吗?
**A**训练数据是在COCO、Object365、RPC、LogoDet等公开数据集中随机抽取的子集小模型精度可能会有一些损失后续我们也会尝试下更小的检测模型。关于主体检测模型的更多信息请参考[主体检测](../application/mainbody_detection.md)。
#### Q1.4.3: 目前使用的主体检测模型检测在某些场景中会有误检?
**A**目前的主体检测模型训练时使用了COCO、Object365、RPC、LogoDet等公开数据集如果被检测数据是类似工业质检等于常见类别差异较大的数据需要基于目前的检测模型重新微调训练。
<a name="1.5图像识别模块"></a>
### 1.5 图像识别模块
#### Q1.5.1 使用`circle loss`还需加`triplet loss`吗?
**A**`circle loss`是统一了样本对学习和分类学习的两种形式,如果是分类学习的形式的话,可以增加`triplet loss`。
#### Q1.5.2 如果不是识别开源的四个方向的图片,该使用哪个识别模型?
**A**建议使用商品识别模型一来是因为商品覆盖的范围比较广被识别的图片是商品的概率更大二来是因为商品识别模型的训练数据使用了5万类别的数据泛化能力更好特征会更鲁棒一些。
#### Q1.5.3 最后使用512维的向量为什么不用1024或者其他维度的呢
**A**使用维度小的向量为了加快计算在实际使用过程中可能使用128甚至更小。一般来说512的维度已经够大能充分表示特征了。
<a name="1.6检索模块"></a>
### 1.6 检索模块
#### Q1.6.1 PaddleClas目前使用的Möbius向量检索算法支持类似于faiss的那种index.add()的功能吗? 另外每次构建新的图都要进行train吗这里的train是为了检索加速还是为了构建相似的图
**A**Mobius提供的检索算法是一种基于图的近似最近邻搜索算法目前支持两种距离计算方式inner product和L2 distance. faiss中提供的index.add功能暂时不支持如果需要增加检索库的内容需要从头重新构建新的index. 在每次构建index时检索算法内部执行的操作是一种类似于train的过程不同于faiss提供的train接口我们命名为build, 主要的目的是为了加速检索的速度。
#### Q1.6.2: PaddleClas 图像识别用于 Eval 的配置文件中,`Query` 和 `Gallery` 配置具体是用于做什么呢?
**A**: `Query``Gallery` 均为数据集配置,其中 `Gallery` 用于配置底库数据,`Query` 用于配置验证集。在进行 Eval 时,首先使用模型对 `Gallery` 底库数据进行前向计算特征向量,特征向量用于构建底库,然后模型对 `Query` 验证集中的数据进行前向计算特征向量,再与底库计算召回率等指标。
<a name="2.实战篇"></a>
## 2. 实战篇
<a name="2.1训练与评估共性问题"></a>
### 2.1 训练与评估共性问题
#### Q2.1.1 PaddleClas 的`train_log`文件在哪里?
**A**:在保存权重的路径中存放了`train.log`。
#### Q2.1.2 模型训练出nan为什么
**A**
1.确保正确加载预训练模型, 最简单的加载方式添加参数`-o Arch.pretrained=True`即可;
2.模型微调时学习率不要太大如设置0.001就好。
#### Q2.1.3 可以对视频中每一帧画面进行逐帧预测吗?
**A**可以但目前PaddleClas并不支持视频输入。可以尝试修改一下PaddleClas代码或者预先将视频逐帧转为图像存储再使用PaddleClas进行预测。
#### Q2.1.4: 数据预处理中,不想对输入数据进行裁剪,该如何设置?或者如何设置剪裁的尺寸。
**A**: PaddleClas 支持的数据预处理算子可在这里查看:`ppcls/data/preprocess/__init__.py`,所有支持的算子均可在配置文件中进行配置,配置的算子名称需要和算子类名一致,参数与对应算子类的构造函数参数一致。如不需要对图像裁剪,则可去掉 `CropImage`、`RandCropImage`,使用 `ResizeImage` 替换即可可通过其参数设置不同的resize方式 使用 `size` 参数则直接将图像缩放至固定大小,使用`resize_short` 参数则会维持图像宽高比进行缩放。设置裁剪尺寸时,可通过 `CropImage` 算子的 `size` 参数,或 `RandCropImage` 算子的 `size` 参数。
#### Q2.1.5: PaddlePaddle 安装后,使用报错,无法导入 paddle 下的任何模块import paddle.xxx是为什么呢
**A**: 首先可以使用以下代码测试 Paddle 是否安装正确:
```python
import paddle
paddle.utils.install_check.run_check(
```
正确安装时,通常会有如下提示:
```
PaddlePaddle is installed successfully! Let's start deep learning with PaddlePaddle now.
```
如未能安装成功,则会有相应问题的提示。
另外在同时安装CPU版本和GPU版本Paddle后由于两个版本存在冲突需要将两个版本全部卸载然后重新安装所需要的版本。
#### Q2.1.6: 使用PaddleClas训练时如何设置仅保存最优模型不想保存中间模型。
**A**: PaddleClas在训练过程中会保存/更新以下三类模型:
1. 最新的模型(`latest.pdopt` `latest.pdparams``latest.pdstates`),当训练意外中断时,可使用最新保存的模型恢复训练;
2. 最优的模型(`best_model.pdopt``best_model.pdparams``best_model.pdstates`
3. 训练过程中一个epoch结束时的断点`epoch_xxx.pdopt``epoch_xxx.pdparams``epoch_xxx.pdstates`)。训练配置文件中 `Global.save_interval` 字段表示该模型的保存间隔。将该字段设置大于总epochs数则不再保存中间断点模型。
#### Q2.1.7: 在训练时,出现如下报错信息:`ERROR: Unexpected segmentation fault encountered in DataLoader workers.`,如何排查解决问题呢?
**A**:尝试将训练配置文件中的字段 `num_workers` 设置为 `0`;尝试将训练配置文件中的字段 `batch_size` 调小一些;检查数据集格式和配置文件中的数据集路径是否正确。
#### Q2.1.8: 如何在训练时使用 `Mixup``Cutmix`
**A**
* `Mixup` 的使用方法请参考 [Mixup](https://github.com/PaddlePaddle/PaddleClas/blob/cf9fc9363877f919996954a63716acfb959619d0/ppcls/configs/ImageNet/DataAugment/ResNet50_Mixup.yaml#L63-L65)`Cuxmix` 请参考 [Cuxmix](https://github.com/PaddlePaddle/PaddleClas/blob/cf9fc9363877f919996954a63716acfb959619d0/ppcls/configs/ImageNet/DataAugment/ResNet50_Cutmix.yaml#L63-L65)。
* 在使用 `Mixup``Cutmix` 时,需要注意:
* 配置文件中的 `Loss.Tranin.CELoss` 需要修改为 `Loss.Tranin.MixCELoss`,可参考 [MixCELoss](https://github.com/PaddlePaddle/PaddleClas/blob/cf9fc9363877f919996954a63716acfb959619d0/ppcls/configs/ImageNet/DataAugment/ResNet50_Cutmix.yaml#L23-L26)
* 使用 `Mixup``Cutmix` 做训练时无法计算训练的精度Acc指标因此需要在配置文件中取消 `Metric.Train.TopkAcc` 字段,可参考 [Metric.Train.TopkAcc](https://github.com/PaddlePaddle/PaddleClas/blob/cf9fc9363877f919996954a63716acfb959619d0/ppcls/configs/ImageNet/DataAugment/ResNet50_Cutmix.yaml#L125-L128)。
#### Q2.1.9: 训练配置yaml文件中字段 `Global.pretrain_model``Global.checkpoints` 分别用于配置什么呢?
**A**
* 当需要 `fine-tune` 时,可以通过字段 `Global.pretrain_model` 配置预训练模型权重文件的路径,预训练模型权重文件后缀名通常为 `.pdparams`
* 在训练过程中训练程序会自动保存每个epoch结束时的断点信息包括优化器信息 `.pdopt` 和模型权重信息 `.pdparams`。在训练过程意外中断等情况下,需要恢复训练时,可以通过字段 `Global.checkpoints` 配置训练过程中保存的断点信息文件,例如通过配置 `checkpoints: ./output/ResNet18/epoch_18` 即可恢复18epoch训练结束时的断点信息PaddleClas将自动加载 `epoch_18.pdopt``epoch_18.pdparams`从19epoch继续训练。
<a name="2.2图像分类"></a>
### 2.2 图像分类
#### Q2.2.1 SSLD中大模型在500M数据上预训练后蒸馏小模型然后在1M数据上蒸馏finetune小模型
**A**:步骤如下:
1. 基于facebook开源的`ResNeXt101-32x16d-wsl`模型 去蒸馏得到了`ResNet50-vd`模型;
2. 用这个`ResNet50-vd`在500W数据集上去蒸馏`MobilNetV3`
3. 考虑到500W的数据集的分布和100W的数据分布不完全一致所以这块在100W上的数据上又finetune了一下精度有微弱的提升。
#### Q2.2.2 训练SwinTransformerloss出现nan
**A**训练SwinTransformer时请使用版本大于等于 `2.1.1``Paddle`,并且加载我们提供的预训练模型,学习率也不宜过大。
<a name="2.3通用检测模块"></a>
### 2.3 通用检测模块
#### Q2.3.1 为什么有一些图片检测出的结果就是原图?
**A**:主体检测模型会返回检测框,但事实上为了让后续的识别模型更加准确,在返回检测框的同时也返回了原图。后续会根据原图或者检测框与库中的图片的相似度排序,相似度最高的库中图片的标签即为被识别图片的标签。
#### Q2.3.2:在直播场景中,需要提供一个直播即时识别画面,能够在延迟几秒内找到特征目标物并用框圈起,这个可以实现吗?
**A**要达到实时的检测效果需要检测速度达到实时性的要求PP-YOLO是Paddle团队提供的轻量级目标检测模型检测速度和精度达到了很好的平衡可以试试PP-YOLO来做检测. 关于PP-YOLO的使用可以参照[PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.1/configs/ppyolo/README_cn.md)。
#### Q2.3.3: 对于未知的标签加入gallery dataset可以用于后续的分类识别无需训练但是如果前面的检测模型对于未知的标签无法定位检测出来是否还是要训练前面的检测模型
**A**如果检测模型在自己的数据集上表现不佳需要在自己的检测数据集上再finetune下
<a name="2.4图像识别模块"></a>
### 2.4 图像识别模块
#### Q2.4.1: 识别模块预测时报`Illegal instruction`错?
**A**:可能是编译生成的库文件与您的环境不兼容,导致程序报错,如果报错,推荐参考[向量检索教程](../../../deploy/vector_search/README.md)重新编译库文件。
#### Q2.4.2: 识别模型怎么在预训练模型的基础上进行微调训练?
**A**:识别模型的微调训练和分类模型的微调训练类似,识别模型可以加载商品的预训练模型,训练过程可以参考[识别模型训练](../tutorials/getting_started_retrieval.md),后续我们也会持续细化这块的文档。
#### Q2.4.3: 训练metric learning时每个epoch中无法跑完所有mini-batch为什么
**A**在训练metric learning时使用的Sampler是DistributedRandomIdentitySampler该Sampler不会采样全部的图片导致会让每一个epoch采样的数据不是所有的数据所以无法跑完显示的mini-batch是正常现象。后续我们会优化下打印的信息尽可能减少给大家带来的困惑。
#### Q2.4.4: 有些图片没有识别出结果,为什么?
**A**在配置文件如inference_product.yaml`IndexProcess.score_thres`中会控制被识别的图片与库中的图片的余弦相似度的最小值。当余弦相似度小于该值时,不会打印结果。您可以根据自己的实际数据调整该值。
<a name="2.5检索模块"></a>
### 2.5 检索模块
#### Q2.5.1: 添加图片后建索引报`assert text_num >= 2`错?
**A**请确保data_file.txt中图片路径和图片名称中间的间隔为单个table而不是空格。
#### Q2.5.2: 新增底库数据需要重新构建索引吗?
**A**:这一版需要重新构建索引,未来版本会支持只构建新增图片的索引。
#### Q2.5.3: Mac重新编译index.so时报错如下clang: error: unsupported option '-fopenmp', 该如何处理?
**A**:该问题已经解决。可以参照[文档](../../../develop/deploy/vector_search/README.md)重新编译 index.so。
#### Q2.5.4: 在 build 检索底库时,参数 `pq_size` 应该如何设置?
**A**`pq_size` 是PQ检索算法的参数。PQ检索算法可以简单理解为“分层”检索算法`pq_size` 是每层的“容量”因此该参数的设置会影响检索性能不过在底库总数据量不太大小于10000张的情况下这个参数对性能的影响很小因此对于大多数使用场景而言在构建底库时无需修改该参数。关于PQ检索算法的更多内容可以查看相关[论文](https://lear.inrialpes.fr/pubs/2011/JDS11/jegou_searching_with_quantization.pdf)。
<a name="2.6模型预测部署"></a>
### 2.6 模型预测部署
#### Q2.6.1: hub serving方式启动某个模块怎么添加该模块的参数呢
**A**:具体可以参考[hub serving参数](../../../deploy/hubserving/clas/params.py)。
#### Q2.6.2: 导出inference模型进行预测部署准确率异常为什么呢
**A**: 该问题通常是由于在导出时未能正确加载模型参数导致的,首先检查模型导出时的日志,是否存在类似下述内容:
```
UserWarning: Skip loading for ***. *** is not found in the provided dict.
```
如果存在,则说明模型权重未能加载成功,请进一步检查配置文件中的 `Global.pretrained_model` 字段,是否正确配置了模型权重文件的路径。模型权重文件后缀名通常为 `pdparams`,注意在配置该路径时无需填写文件后缀名。
#### Q2.6.3: 如何将模型转为 `ONNX` 格式?
**A**Paddle支持两种转ONNX格式模型的方式且依赖于 `paddle2onnx` 工具,首先需要安装 `paddle2onnx`
```shell
pip install paddle2onnx
```
* 从 inference model 转为 ONNX 格式模型:
以动态图导出的 `combined` 格式 inference model包含 `.pdmodel``.pdiparams` 两个文件)为例,使用以下命令进行模型格式转换:
```shell
paddle2onnx --model_dir ${model_path} --model_filename ${model_path}/inference.pdmodel --params_filename ${model_path}/inference.pdiparams --save_file ${save_path}/model.onnx --enable_onnx_checker True
```
上述命令中:
* `model_dir`:该参数下需要包含 `.pdmodel``.pdiparams` 两个文件;
* `model_filename`:该参数用于指定参数 `model_dir` 下的 `.pdmodel` 文件路径;
* `params_filename`:该参数用于指定参数 `model_dir` 下的 `.pdiparams` 文件路径;
* `save_file`:该参数用于指定转换后的模型保存目录路径。
关于静态图导出的非 `combined` 格式的 inference model通常包含文件 `__model__` 和多个参数文件)转换模型格式,以及更多参数说明请参考 paddle2onnx 官方文档 [paddle2onnx](https://github.com/PaddlePaddle/Paddle2ONNX/blob/develop/README_zh.md#%E5%8F%82%E6%95%B0%E9%80%89%E9%A1%B9)。
* 直接从模型组网代码导出ONNX格式模型
以动态图模型组网代码为例,模型类为继承于 `paddle.nn.Layer` 的子类,代码如下所示:
```python
import paddle
from paddle.static import InputSpec
class SimpleNet(paddle.nn.Layer):
def __init__(self):
pass
def forward(self, x):
pass
net = SimpleNet()
x_spec = InputSpec(shape=[None, 3, 224, 224], dtype='float32', name='x')
paddle.onnx.export(layer=net, path="./SimpleNet", input_spec=[x_spec])
```
其中:
* `InputSpec()` 函数用于描述模型输入的签名信息,包括输入数据的 `shape`、`type` 和 `name`(可省略);
* `paddle.onnx.export()` 函数需要指定模型组网对象 `net`,导出模型的保存路径 `save_path`,模型的输入数据描述 `input_spec`
需要注意,`paddlepaddle` 版本需大于 `2.0.0`。关于 `paddle.onnx.export()` 函数的更多参数说明请参考[paddle.onnx.export](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/onnx/export_cn.html#export)。

View File

@ -0,0 +1,260 @@
# 30分钟玩转PaddleClas进阶版
此处提供了专业用户在linux操作系统上使用PaddleClas的快速上手教程主要内容基于CIFAR-100数据集快速体验不同模型的训练、加载不同预训练模型、SSLD知识蒸馏方案和数据增广的效果。请事先参考[安装指南](../installation/install_paddleclas.md)配置运行环境和克隆PaddleClas代码。
## 一、数据和模型准备
### 1.1 数据准备
* 进入PaddleClas目录。
```
cd path_to_PaddleClas
```
#### 1.1.1 准备CIFAR100
* 进入`dataset/`目录下载并解压CIFAR100数据集。
```shell
cd dataset
wget https://paddle-imagenet-models-name.bj.bcebos.com/data/CIFAR100.tar
tar -xf CIFAR100.tar
cd ../
```
## 二、模型训练
### 2.1 单标签训练
#### 2.1.1 零基础训练:不加载预训练模型的训练
* 基于ResNet50_vd模型训练脚本如下所示。
```shell
export CUDA_VISIBLE_DEVICES=0,1,2,3
python3 -m paddle.distributed.launch \
--gpus="0,1,2,3" \
tools/train.py \
-c ./ppcls/configs/quick_start/professional/ResNet50_vd_CIFAR100.yaml \
-o Global.output_dir="output_CIFAR"
```
验证集的最高准确率为0.415左右。
#### 2.1.2 迁移学习
* 基于ImageNet1k分类预训练模型ResNet50_vd_pretrained(准确率79.12\%)进行微调,训练脚本如下所示。
```shell
export CUDA_VISIBLE_DEVICES=0,1,2,3
python3 -m paddle.distributed.launch \
--gpus="0,1,2,3" \
tools/train.py \
-c ./ppcls/configs/quick_start/professional/ResNet50_vd_CIFAR100.yaml \
-o Global.output_dir="output_CIFAR" \
-o Arch.pretrained=True
```
验证集最高准确率为0.718左右加载预训练模型之后CIFAR100数据集精度大幅提升绝对精度涨幅30\%。
* 基于ImageNet1k分类预训练模型ResNet50_vd_ssld_pretrained(准确率82.39\%)进行微调,训练脚本如下所示。
```shell
export CUDA_VISIBLE_DEVICES=0,1,2,3
python3 -m paddle.distributed.launch \
--gpus="0,1,2,3" \
tools/train.py \
-c ./ppcls/configs/quick_start/professional/ResNet50_vd_CIFAR100.yaml \
-o Global.output_dir="output_CIFAR" \
-o Arch.pretrained=True \
-o Arch.use_ssld=True
```
最终CIFAR100验证集上精度指标为0.73相对于79.12\%预训练模型的微调结构新数据集指标可以再次提升1.2\%。
* 替换backbone为MobileNetV3_large_x1_0进行微调训练脚本如下所示。
```shell
export CUDA_VISIBLE_DEVICES=0,1,2,3
python3 -m paddle.distributed.launch \
--gpus="0,1,2,3" \
tools/train.py \
-c ./ppcls/configs/quick_start/professional/MobileNetV3_large_x1_0_CIFAR100_finetune.yaml \
-o Global.output_dir="output_CIFAR" \
-o Arch.pretrained=True
```
验证集最高准确率为0.601左右, 较ResNet50_vd低近12%。
## 三、数据增广
PaddleClas包含了很多数据增广的方法如Mixup、Cutout、RandomErasing等具体的方法可以参考[数据增广的章节](../algorithm_introduction/DataAugmentation.md)。
### 数据增广的尝试-Mixup
基于`3.3节`中的训练方法结合Mixup的数据增广方式进行训练具体的训练脚本如下所示。
```shell
export CUDA_VISIBLE_DEVICES=0,1,2,3
python3 -m paddle.distributed.launch \
--gpus="0,1,2,3" \
tools/train.py \
-c ./ppcls/configs/quick_start/professional/ResNet50_vd_mixup_CIFAR100_finetune.yaml \
-o Global.output_dir="output_CIFAR"
```
最终CIFAR100验证集上的精度为0.73使用数据增广可以使得模型精度再次提升约1.2\%。
* **注意**
* 其他数据增广的配置文件可以参考`ppcls/configs/DataAugment`中的配置文件。
* 训练CIFAR100的迭代轮数较少因此进行训练时验证集的精度指标可能会有1\%左右的波动。
## 四、知识蒸馏
PaddleClas包含了自研的SSLD知识蒸馏方案具体的内容可以参考[知识蒸馏章节](../algorithm_introduction/knowledge_distillation.md), 本小节将尝试使用知识蒸馏技术对MobileNetV3_large_x1_0模型进行训练使用`2.1.2小节`训练得到的ResNet50_vd模型作为蒸馏所用的教师模型首先将`2.1.2小节`训练得到的ResNet50_vd模型保存到指定目录脚本如下。
```shell
mkdir pretrained
cp -r output_CIFAR/ResNet50_vd/best_model.pdparams ./pretrained/
```
配置文件中模型名字、教师模型哈学生模型的配置、预训练地址配置以及freeze_params配置如下其中freeze_params_list中的两个值分别代表教师模型和学生模型是否冻结参数训练。
```yaml
Arch:
name: "DistillationModel"
# if not null, its lengths should be same as models
pretrained_list:
# if not null, its lengths should be same as models
freeze_params_list:
- True
- False
models:
- Teacher:
name: ResNet50_vd
pretrained: "./pretrained/best_model"
- Student:
name: MobileNetV3_large_x1_0
pretrained: True
```
Loss配置如下其中训练Loss是学生模型的输出和教师模型的输出的交叉熵、验证Loss是学生模型的输出和真实标签的交叉熵。
```yaml
Loss:
Train:
- DistillationCELoss:
weight: 1.0
model_name_pairs:
- ["Student", "Teacher"]
Eval:
- DistillationGTCELoss:
weight: 1.0
model_names: ["Student"]
```
最终的训练脚本如下所示。
```shell
export CUDA_VISIBLE_DEVICES=0,1,2,3
python3 -m paddle.distributed.launch \
--gpus="0,1,2,3" \
tools/train.py \
-c ./ppcls/configs/quick_start/professional/R50_vd_distill_MV3_large_x1_0_CIFAR100.yaml \
-o Global.output_dir="output_CIFAR"
```
最终CIFAR100验证集上的精度为64.4\%使用教师模型进行知识蒸馏MobileNetV3的精度涨幅4.3\%。
* **注意**
* 蒸馏过程中教师模型使用的预训练模型为CIFAR100数据集上的训练结果学生模型使用的是ImageNet1k数据集上精度为75.32\%的MobileNetV3_large_x1_0预训练模型。
* 该蒸馏过程无须使用真实标签所以可以使用更多的无标签数据在使用过程中可以将无标签数据生成假的train_list.txt然后与真实的train_list.txt进行合并, 用户可以根据自己的数据自行体验。
## 五、模型评估与推理
### 5.1 单标签分类模型评估与推理
#### 5.1.1 单标签分类模型评估。
训练好模型之后,可以通过以下命令实现对模型精度的评估。
```bash
python3 tools/eval.py \
-c ./ppcls/configs/quick_start/professional/ResNet50_vd_CIFAR100.yaml \
-o Global.pretrained_model="output_CIFAR/ResNet50_vd/best_model"
```
#### 5.1.2 单标签分类模型预测
模型训练完成之后,可以加载训练得到的预训练模型,进行模型预测。在模型库的 `tools/infer.py` 中提供了完整的示例,只需执行下述命令即可完成模型预测:
```python
python3 tools/infer.py \
-c ./ppcls/configs/quick_start/professional/ResNet50_vd_CIFAR100.yaml \
-o Infer.infer_imgs=./dataset/CIFAR100/test/0/0001.png \
-o Global.pretrained_model=output_CIFAR/ResNet50_vd/best_model
```
#### 5.1.3 单标签分类使用inference模型进行模型推理
通过导出inference模型PaddlePaddle支持使用预测引擎进行预测推理。接下来介绍如何用预测引擎进行推理
首先,对训练好的模型进行转换:
```bash
python3 tools/export_model.py \
-c ./ppcls/configs/quick_start/professional/ResNet50_vd_CIFAR100.yaml \
-o Global.pretrained_model=output_CIFAR/ResNet50_vd/best_model
```
* 默认会在`inference`文件夹下生成`inference.pdiparams`、`inference.pdmodel`和`inference.pdiparams.info`文件。
使用预测引擎进行推理:
进入deploy目录下
```bash
cd deploy
```
更改inference_cls.yaml文件由于训练CIFAR100采用的分辨率是32x32所以需要改变相关的分辨率最终配置文件中的图像预处理如下
```yaml
PreProcess:
transform_ops:
- ResizeImage:
resize_short: 36
- CropImage:
size: 32
- NormalizeImage:
scale: 0.00392157
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
```
执行命令进行预测由于默认class_id_map_file是ImageNet数据集的映射文件所以此处需要置None。
```bash
python3 python/predict_cls.py \
-c configs/inference_cls.yaml \
-o Global.infer_imgs=../dataset/CIFAR100/test/0/0001.png \
-o PostProcess.Topk.class_id_map_file=None
```