Merge branch 'PaddlePaddle:develop' into develop

pull/1154/head
lilithzhou 2021-08-18 17:41:12 +08:00 committed by GitHub
commit f64188e4ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 480 additions and 138 deletions

View File

@ -8,7 +8,7 @@
**近期更新**
- 2021.07.08、07.27 添加26个[FAQ](docs/zh_CN/faq_series/faq_2021_s2.md)
- 2021.08.11 更新7个[FAQ](docs/zh_CN/faq_series/faq_2021_s2.md)。
- 2021.06.29 添加Swin-transformer系列模型ImageNet1k数据集上Top1 acc最高精度可达87.2%支持训练预测评估与whl包部署预训练模型可以从[这里](docs/zh_CN/models/models_intro.md)下载。
- 2021.06.22,23,24 PaddleClas官方研发团队带来技术深入解读三日直播课。课程回放[https://aistudio.baidu.com/aistudio/course/introduce/24519](https://aistudio.baidu.com/aistudio/course/introduce/24519)
- 2021.06.16 PaddleClas v2.2版本升级集成Metric learning向量检索等组件。新增商品识别、动漫人物识别、车辆识别和logo识别等4个图像识别应用。新增LeViT、Twins、TNT、DLA、HarDNet、RedNet系列30个预训练模型。

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -167,4 +167,22 @@ python tools/export_model.py -c configs/ppyolo/ppyolov2_r50vd_dcn_365e_coco.yml
更多模型导出教程,请参考:[EXPORT_MODEL](https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.1/deploy/EXPORT_MODEL.md)
导出模型之后在主体检测与识别任务中就可以将检测模型的路径更改为该inference模型路径完成预测。图像识别快速体验可以参考[图像识别快速开始教程](../tutorials/quick_start_recognition.md)。
最终,目录`inference/ppyolov2_r50vd_dcn_365e_coco`中包含`inference.pdiparams`, `inference.pdiparams.info` 以及 `inference.pdmodel` 文件,其中`inference.pdiparams`为保存的inference模型权重文件`inference.pdmodel`为保存的inference模型结构文件。
导出模型之后在主体检测与识别任务中就可以将检测模型的路径更改为该inference模型路径完成预测。
以商品识别为例,其配置文件为[inference_product.yaml](../../../deploy/configs/inference_product.yaml),修改其中的`Global.det_inference_model_dir`字段为导出的主体检测inference模型目录参考[图像识别快速开始教程](../tutorials/quick_start_recognition.md),即可完成商品检测与识别过程。
### FAQ
#### Q可以使用其他的主体检测模型结构吗
* A可以的但是目前的检测预处理过程仅适配yolo系列的预处理因此在使用的时候建议优先使用yolo系列的模型进行训练如果希望使用faster rcnn等其他系列的模型需要按照PaddleDetection的数据预处理修改下预处理逻辑这块如果您有需求或者有问题的话欢迎提issue或者在群里反馈。
#### Q可以修改主体检测的预测尺度吗
* A可以的但是需要注意2个地方
* PaddleClas中提供的主体检测模型是基于640x640的分辨率去训练的因此预测的时候也是默认使用640x640的分辨率进行预测使用其他分辨率预测的话精度会有所降低。
* 在模型导出的时候,建议也修改下模型导出的分辨率,保持模型导出、模型预测的分辨率一致。

View File

@ -1,124 +1,269 @@
# 图像识别常见问题汇总 - 2021 第2季
# PaddleClas 相关常见问题汇总 - 2021 第2季
## 写在前面
* 我们收集整理了开源以来在issues和用户群中的常见问题并且给出了简要解答旨在为广大用户提供一些参考也希望帮助大家少走一些弯路。
* 图像分类、识别、检索领域大佬众多,模型和论文更新速度也很快,本文档回答主要依赖有限的项目实践,难免挂一漏万,如有遗漏和不足,也希望有识之士帮忙补充和修正,万分感谢。
## 目录
* [第1期](#第1期)(2021.07.08)
* [第2期](#第2期)(2021.07.27)
* [近期更新](#近期更新)(2021.08.11)
* [精选](#精选)
* [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="第1期"></a>
## 第1期
<a name="近期更新"></a>
## 近期更新
### Q1.1: 目前使用的主体检测模型检测在某些场景中会有误检?
#### Q2.6.2: 导出inference模型进行预测部署准确率异常为什么呢
**A**: 该问题通常是由于在导出时未能正确加载模型参数导致的,首先检查模型导出时的日志,是否存在类似下述内容:
```
UserWarning: Skip loading for ***. *** is not found in the provided dict.
```
如果存在,则说明模型权重未能加载成功,请进一步检查配置文件中的 `Global.pretrained_model` 字段,是否正确配置了模型权重文件的路径。模型权重文件后缀名通常为 `pdparams`,注意在配置该路径时无需填写文件后缀名。
**A**目前的主体检测模型训练时使用了COCO、Object365、RPC、LogoDet等公开数据集如果被检测数据是类似工业质检等于常见类别差异较大的数据需要基于目前的检测模型重新微调训练。
#### Q2.1.4: 数据预处理中,不想对输入数据进行裁剪,该如何设置?或者如何设置剪裁的尺寸。
**A**: PaddleClas 支持的数据预处理算子可在这里查看:`ppcls/data/preprocess/__init__.py`,所有支持的算子均可在配置文件中进行配置,配置的算子名称需要和算子类名一致,参数与对应算子类的构造函数参数一致。如不需要对图像裁剪,则可去掉 `CropImage`、`RandCropImage`,使用 `ResizeImage` 替换即可可通过其参数设置不同的resize方式 使用 `size` 参数则直接将图像缩放至固定大小,使用`resize_short` 参数则会维持图像宽高比进行缩放。设置裁剪尺寸时,可通过 `CropImage` 算子的 `size` 参数,或 `RandCropImage` 算子的 `size` 参数。
### Q1.2: 添加图片后建索引报`assert text_num >= 2`错?
#### 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`。因此,太过“久远”的梯度信息对当前的参考意义很小,而“最近”的历史梯度信息对当前影响更大,这也是符合直觉的。
**A**请确保data_file.txt中图片路径和图片名称中间的间隔为单个table而不是空格。
<div align="center">
<img src="../../images/faq/momentum.jpeg" width="400">
</div>
### Q1.3: 识别模块预测时报`Illegal instruction`错?
*该图来自 `https://blog.csdn.net/tsyccnh/article/details/76270707`*
**A**:可能是编译生成的库文件与您的环境不兼容,导致程序报错,如果报错,推荐参考[向量检索教程](../../../deploy/vector_search/README.md)重新编译库文件。
通过引入动量的概念,在参数更新时考虑了历史更新的影响,因此可以加快收敛速度,也改善了 `SGD` 优化器带来的损失cost、loss震荡问题
### Q1.4 主体检测是每次只输出一个主体检测框吗?
#### Q1.1.4: PaddleClas 是否有 `Fixing the train-test resolution discrepancy` 这篇论文的实现呢?
**A**: 目前 PaddleClas 没有实现。如果需要可以尝试自己修改代码。简单来说该论文所提出的思想是使用较大分辨率作为输入对已经训练好的模型最后的FC层进行fine-tune。具体操作上首先在较低分辨率的数据集上对模型网络进行训练完成训练后对网络除最后的FC层外的其他层的权重设置参数 `stop_gradient=True`然后使用较大分辨率的输入对网络进行fine-tune训练。
**A**主体检测这块的输出数量是可以通过配置文件配置的。在配置文件中Global.threshold控制检测的阈值小于该阈值的检测框被舍弃Global.max_det_results控制最大返回的结果数这两个参数共同决定了输出检测框的数量。
#### Q1.6.2: PaddleClas 图像识别用于 Eval 的配置文件中,`Query` 和 `Gallery` 配置具体是用于做什么呢?
**A**: `Query``Gallery` 均为数据集配置,其中 `Gallery` 用于配置底库数据,`Query` 用于配置验证集。在进行 Eval 时,首先使用模型对 `Gallery` 底库数据进行前向计算特征向量,特征向量用于构建底库,然后模型对 `Query` 验证集中的数据进行前向计算特征向量,再与底库计算召回率等指标。
### Q1.5 训练主体检测模型的数据是如何选择的?换成更小的模型会有损精度吗?
#### 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后由于两个版本存在冲突需要将两个版本全部卸载然后重新安装所需要的版本。
**A**训练数据是在COCO、Object365、RPC、LogoDet等公开数据集中随机抽取的子集小模型精度可能会有一些损失后续我们也会尝试下更小的检测模型。关于主体检测模型的更多信息请参考[主体检测](../application/mainbody_detection.md)。
#### 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数则不再保存中间断点模型。
### Q1.6 识别模型怎么在预训练模型的基础上进行微调训练?
<a name="精选"></a>
## 精选
**A**:识别模型的微调训练和分类模型的微调训练类似,识别模型可以加载商品的预训练模型],训练过程可以参考[识别模型训练](../tutorials/getting_started_retrieval.md),后续我们也会持续细化这块的文档。
<a name="1.理论篇"></a>
## 1. 理论篇
### Q1.7 PaddleClas和PaddleDetection区别
<a name="1.1PaddleClas基础知识"></a>
### 1.1 PaddleClas基础知识
#### Q1.1.1 PaddleClas和PaddleDetection区别
**A**PaddleClas是一个兼主体检测、图像分类、图像检索于一体的图像识别repo用于解决大部分图像识别问题用户可以很方便的使用PaddleClas来解决小样本、多类别的图像识别问题。PaddleDetection提供了目标检测、关键点检测、多目标跟踪等能力方便用户定位图像中的感兴趣的点和区域被广泛应用于工业质检、遥感图像检测、无人巡检等项目。
### Q1.8 PaddleClas 2.2和PaddleClas 2.1完全兼容吗?
#### 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.9 训练metric learning时每个epoch中无法跑完所有mini-batch为什么
#### 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`。因此,太过“久远”的梯度信息对当前的参考意义很小,而“最近”的历史梯度信息对当前影响更大,这也是符合直觉的。
**A**在训练metric learning时使用的Sampler是DistributedRandomIdentitySampler该Sampler不会采样全部的图片导致会让每一个epoch采样的数据不是所有的数据所以无法跑完显示的mini-batch是正常现象。后续我们会优化下打印的信息尽可能减少给大家带来的困惑。
<div align="center">
<img src="../../images/faq/momentum.jpeg" width="400">
</div>
### Q1.10 有些图片没有识别出结果,为什么?
通过引入动量的概念,在参数更新时考虑了历史更新的影响,因此可以加快收敛速度,也改善了 `SGD` 优化器带来的损失cost、loss震荡问题。
**A**在配置文件如inference_product.yaml`IndexProcess.score_thres`中会控制被识别的图片与库中的图片的余弦相似度的最小值。当余弦相似度小于该值时,不会打印结果。您可以根据自己的实际数据调整该值。
#### Q1.1.4: PaddleClas 是否有 `Fixing the train-test resolution discrepancy` 这篇论文的实现呢?
**A**: 目前 PaddleClas 没有实现。如果需要可以尝试自己修改代码。简单来说该论文所提出的思想是使用较大分辨率作为输入对已经训练好的模型最后的FC层进行fine-tune。具体操作上首先在较低分辨率的数据集上对模型网络进行训练完成训练后对网络除最后的FC层外的其他层的权重设置参数 `stop_gradient=True`然后使用较大分辨率的输入对网络进行fine-tune训练。
### Q1.11 为什么有一些图片检测出的结果就是原图?
<a name="1.2骨干网络和预训练模型库"></a>
### 1.2 骨干网络和预训练模型库
**A**:主体检测模型会返回检测框,但事实上为了让后续的识别模型更加准确,在返回检测框的同时也返回了原图。后续会根据原图或者检测框与库中的图片的相似度排序,相似度最高的库中图片的标签即为被识别图片的标签。
<a name="1.3图像分类"></a>
### 1.3 图像分类
### Q1.12 使用`circle loss`还需加`triplet loss`吗?
#### 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.13 hub serving方式启动某个模块怎么添加该模块的参数呢
**A**:具体可以参考[hub serving参数](../../../deploy/hubserving/clas/params.py)。
### Q1.14 模型训练出nan为什么
**A**
1.确保正确加载预训练模型, 最简单的加载方式添加参数`-o Arch.pretrained=True`即可;
2.模型微调时学习率不要太大如设置0.001就好。
### Q1.15 SSLD中大模型在500M数据上预训练后蒸馏小模型然后在1M数据上蒸馏finetune小模型
**A**:步骤如下:
1.基于facebook开源的`ResNeXt101-32x16d-wsl`模型 去蒸馏得到了`ResNet50-vd`模型;
2.用这个`ResNet50-vd`在500W数据集上去蒸馏`MobilNetV3`
3.考虑到500W的数据集的分布和100W的数据分布不完全一致所以这块在100W上的数据上又finetune了一下精度有微弱的提升。
### Q1.16 如果不是识别开源的四个方向的图片,该使用哪个识别模型?
#### Q1.5.2 如果不是识别开源的四个方向的图片,该使用哪个识别模型?
**A**建议使用商品识别模型一来是因为商品覆盖的范围比较广被识别的图片是商品的概率更大二来是因为商品识别模型的训练数据使用了5万类别的数据泛化能力更好特征会更鲁棒一些。
### Q1.17 最后使用512维的向量为什么不用1024或者其他维度的呢
#### Q1.5.3 最后使用512维的向量为什么不用1024或者其他维度的呢
**A**使用维度小的向量为了加快计算在实际使用过程中可能使用128甚至更小。一般来说512的维度已经够大能充分表示特征了。
### Q1.18 训练SwinTransformerloss出现nan
**A**训练SwinTransformer的话需要使用paddle-dev去训练安装方式参考[paddlepaddle安装方式](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/develop/install/pip/linux-pip.html)后续paddlepaddle-2.1也会同时支持。
### Q1.19 新增底库数据需要重新构建索引吗?
**A**:这一版需要重新构建索引,未来版本会支持只构建新增图片的索引。
### Q1.20 PaddleClas 的`train_log`文件在哪里?
**A**:在保存权重的路径中存放了`train.log`。
<a name="第2期"></a>
## 第2期
### Q2.1 PaddleClas目前使用的Möbius向量检索算法支持类似于faiss的那种index.add()的功能吗? 另外每次构建新的图都要进行train吗这里的train是为了检索加速还是为了构建相似的图
<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, 主要的目的是为了加速检索的速度。
### Q2.2 可以对视频中每一帧画面进行逐帧预测吗?
#### 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.3:在直播场景中,需要提供一个直播即时识别画面,能够在延迟几秒内找到特征目标物并用框圈起,这个可以实现吗?
**A**要达到实时的检测效果需要检测速度达到实时性的要求PPyolo是Paddle团队提供的轻量级目标检测模型检测速度和精度达到了很好的平衡可以试试ppyolo来做检测. 关于ppyolo的使用可以参照 https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.1/configs/ppyolo/README_cn.md
#### Q2.1.4: 数据预处理中,不想对输入数据进行裁剪,该如何设置?或者如何设置剪裁的尺寸。
**A**: PaddleClas 支持的数据预处理算子可在这里查看:`ppcls/data/preprocess/__init__.py`,所有支持的算子均可在配置文件中进行配置,配置的算子名称需要和算子类名一致,参数与对应算子类的构造函数参数一致。如不需要对图像裁剪,则可去掉 `CropImage`、`RandCropImage`,使用 `ResizeImage` 替换即可可通过其参数设置不同的resize方式 使用 `size` 参数则直接将图像缩放至固定大小,使用`resize_short` 参数则会维持图像宽高比进行缩放。设置裁剪尺寸时,可通过 `CropImage` 算子的 `size` 参数,或 `RandCropImage` 算子的 `size` 参数。
### Q2.4: 对于未知的标签加入gallery dataset可以用于后续的分类识别无需训练但是如果前面的检测模型对于未知的标签无法定位检测出来是否还是要训练前面的检测模型
#### 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数则不再保存中间断点模型。
<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下
### Q2.5: Mac重新编译index.so时报错如下clang: error: unsupported option '-fopenmp', 该如何处理?
**A**该问题已经解决。Mac编译index.so可以参照文档 https://github.com/PaddlePaddle/PaddleClas/blob/develop/deploy/vector_search/README.md
<a name="2.4图像识别模块"></a>
### 2.4 图像识别模块
### Q2.6: PaddleClas有提供调整图片亮度对比度饱和度色调等方面的数据增强吗
**A**PaddleClas提供了多种数据增广方式 可分为3类1. 图像变换类: AutoAugment, RandAugment; 2. 图像裁剪类: CutOut、RandErasing、HideAndSeek、GridMask3. 图像混叠类Mixup, Cutmix. 其中Randangment提供了多种数据增强方式的随机组合可以满足亮度、对比度、饱和度、色调等多方面的数据增广需求
#### 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。
<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`,注意在配置该路径时无需填写文件后缀名。

View File

@ -244,7 +244,7 @@ python3 python/predict_cls.py \
-c configs/inference_cls.yaml \
-o Global.infer_imgs=../dataset/flowers102/jpg/image_00001.jpg \
-o Global.inference_model_dir=../inference/ \
-o PostProcess.class_id_map_file=None
-o PostProcess.Topk.class_id_map_file=None
其中:

View File

@ -128,7 +128,7 @@ python3 -m paddle.distributed.launch \
PaddleClas包含了自研的SSLD知识蒸馏方案具体的内容可以参考[知识蒸馏章节](../advanced_tutorials/distillation/distillation.md), 本小节将尝试使用知识蒸馏技术对MobileNetV3_large_x1_0模型进行训练使用`2.1.2小节`训练得到的ResNet50_vd模型作为蒸馏所用的教师模型首先将`2.1.2小节`训练得到的ResNet50_vd模型保存到指定目录脚本如下。
```shell
mkdir pretrained
mkdir pretrained
cp -r output_CIFAR/ResNet50_vd/best_model.pdparams ./pretrained/
```
@ -256,5 +256,5 @@ PreProcess:
python3 python/predict_cls.py \
-c configs/inference_cls.yaml \
-o Global.infer_imgs=../dataset/CIFAR100/test/0/0001.png \
-o PostProcess.class_id_map_file=None
-o PostProcess.Topk.class_id_map_file=None
```

View File

View File

@ -12,15 +12,9 @@ class Identity(nn.Layer):
class TheseusLayer(nn.Layer):
def __init__(self, *args, return_patterns=None, **kwargs):
def __init__(self, *args, **kwargs):
super(TheseusLayer, self).__init__()
self.res_dict = None
if return_patterns is not None:
self._update_res(return_patterns)
def forward(self, *input, res_dict=None, **kwargs):
if res_dict is not None:
self.res_dict = res_dict
self.res_dict = {}
# stop doesn't work when stop layer has a parallel branch.
def stop_after(self, stop_layer_name: str):
@ -38,33 +32,43 @@ class TheseusLayer(nn.Layer):
stop_layer_name)
return after_stop
def _update_res(self, return_layers):
def update_res(self, return_patterns):
if not return_patterns or isinstance(self, WrapLayer):
return
for layer_i in self._sub_layers:
layer_name = self._sub_layers[layer_i].full_name()
for return_pattern in return_layers:
if return_layers is not None and re.match(return_pattern,
layer_name):
self._sub_layers[layer_i].register_forward_post_hook(
self._save_sub_res_hook)
if isinstance(self._sub_layers[layer_i], (nn.Sequential, nn.LayerList)):
self._sub_layers[layer_i] = wrap_theseus(self._sub_layers[layer_i])
self._sub_layers[layer_i].res_dict = self.res_dict
self._sub_layers[layer_i].update_res(return_patterns)
else:
for return_pattern in return_patterns:
if re.match(return_pattern, layer_name):
if not isinstance(self._sub_layers[layer_i], TheseusLayer):
self._sub_layers[layer_i] = wrap_theseus(self._sub_layers[layer_i])
self._sub_layers[layer_i].register_forward_post_hook(
self._sub_layers[layer_i]._save_sub_res_hook)
self._sub_layers[layer_i].res_dict = self.res_dict
if isinstance(self._sub_layers[layer_i], TheseusLayer):
self._sub_layers[layer_i].res_dict = self.res_dict
self._sub_layers[layer_i].update_res(return_patterns)
def replace_sub(self, layer_name_pattern, replace_function,
recursive=True):
for k in self._sub_layers.keys():
layer_name = self._sub_layers[k].full_name()
def _save_sub_res_hook(self, layer, input, output):
self.res_dict[layer.full_name()] = output
def replace_sub(self, layer_name_pattern, replace_function, recursive=True):
for layer_i in self._sub_layers:
layer_name = self._sub_layers[layer_i].full_name()
if re.match(layer_name_pattern, layer_name):
self._sub_layers[k] = replace_function(self._sub_layers[k])
self._sub_layers[layer_i] = replace_function(self._sub_layers[layer_i])
if recursive:
if isinstance(self._sub_layers[k], TheseusLayer):
self._sub_layers[k].replace_sub(
if isinstance(self._sub_layers[layer_i], TheseusLayer):
self._sub_layers[layer_i].replace_sub(
layer_name_pattern, replace_function, recursive)
elif isinstance(self._sub_layers[k],
nn.Sequential) or isinstance(
self._sub_layers[k], nn.LayerList):
for kk in self._sub_layers[k]._sub_layers.keys():
self._sub_layers[k]._sub_layers[kk].replace_sub(
elif isinstance(self._sub_layers[layer_i], (nn.Sequential, nn.LayerList)):
for layer_j in self._sub_layers[layer_i]._sub_layers:
self._sub_layers[layer_i]._sub_layers[layer_j].replace_sub(
layer_name_pattern, replace_function, recursive)
else:
pass
'''
example of replace function:
@ -78,3 +82,40 @@ class TheseusLayer(nn.Layer):
return new_conv
'''
class WrapLayer(TheseusLayer):
def __init__(self, sub_layer):
super(WrapLayer, self).__init__()
self.sub_layer = sub_layer
self.name = sub_layer.full_name()
def full_name(self):
return self.name
def forward(self, *inputs, **kwargs):
return self.sub_layer(*inputs, **kwargs)
def update_res(self, return_patterns):
if not return_patterns or not isinstance(self.sub_layer, (nn.Sequential, nn.LayerList)):
return
for layer_i in self.sub_layer._sub_layers:
if isinstance(self.sub_layer._sub_layers[layer_i], (nn.Sequential, nn.LayerList)):
self.sub_layer._sub_layers[layer_i] = wrap_theseus(self.sub_layer._sub_layers[layer_i])
self.sub_layer._sub_layers[layer_i].res_dict = self.res_dict
self.sub_layer._sub_layers[layer_i].update_res(return_patterns)
layer_name = self.sub_layer._sub_layers[layer_i].full_name()
for return_pattern in return_patterns:
if re.match(return_pattern, layer_name):
self.sub_layer._sub_layers[layer_i].res_dict = self.res_dict
self.sub_layer._sub_layers[layer_i].register_forward_post_hook(
self._sub_layers[layer_i]._save_sub_res_hook)
if isinstance(self.sub_layer._sub_layers[layer_i], TheseusLayer):
self.sub_layer._sub_layers[layer_i].update_res(return_patterns)
def wrap_theseus(sub_layer):
wrapped_layer = WrapLayer(sub_layer)
return wrapped_layer

View File

@ -111,7 +111,7 @@ class VGGNet(TheseusLayer):
model: nn.Layer. Specific VGG model depends on args.
"""
def __init__(self, config, stop_grad_layers=0, class_num=1000):
def __init__(self, config, stop_grad_layers=0, class_num=1000, return_patterns=None):
super().__init__()
self.stop_grad_layers = stop_grad_layers
@ -138,7 +138,7 @@ class VGGNet(TheseusLayer):
self.fc2 = Linear(4096, 4096)
self.fc3 = Linear(4096, class_num)
def forward(self, inputs):
def forward(self, inputs, res_dict=None):
x = self.conv_block_1(inputs)
x = self.conv_block_2(x)
x = self.conv_block_3(x)
@ -152,6 +152,9 @@ class VGGNet(TheseusLayer):
x = self.relu(x)
x = self.drop(x)
x = self.fc3(x)
if self.res_dict and res_dict is not None:
for res_key in list(self.res_dict):
res_dict[res_key] = self.res_dict.pop(res_key)
return x

View File

@ -12,7 +12,7 @@ MODEL_URLS = {
"ResNeXt101_32x8d_wsl":
"https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/ResNeXt101_32x8d_wsl_pretrained.pdparams",
"ResNeXt101_32x16d_wsl":
"https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/ResNeXt101_32x816_wsl_pretrained.pdparams",
"https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/ResNeXt101_32x16_wsl_pretrained.pdparams",
"ResNeXt101_32x32d_wsl":
"https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/ResNeXt101_32x32d_wsl_pretrained.pdparams",
"ResNeXt101_32x48d_wsl":

View File

@ -24,6 +24,7 @@ Loss:
Train:
- CELoss:
weight: 1.0
epsilon: 0.1
Eval:
- CELoss:
weight: 1.0
@ -35,9 +36,10 @@ Optimizer:
lr:
name: Cosine
learning_rate: 0.8
warmup_epoch: 5
regularizer:
name: 'L2'
coeff: 0.0004
coeff: 0.00004
# data loader for train and eval

View File

@ -24,6 +24,7 @@ Loss:
Train:
- CELoss:
weight: 1.0
epsilon: 0.1
Eval:
- CELoss:
weight: 1.0
@ -35,9 +36,10 @@ Optimizer:
lr:
name: Cosine
learning_rate: 0.8
warmup_epoch: 5
regularizer:
name: 'L2'
coeff: 0.0004
coeff: 0.00004
# data loader for train and eval

View File

@ -24,6 +24,7 @@ Loss:
Train:
- CELoss:
weight: 1.0
epsilon: 0.1
Eval:
- CELoss:
weight: 1.0
@ -35,9 +36,10 @@ Optimizer:
lr:
name: Cosine
learning_rate: 0.8
warmup_epoch: 5
regularizer:
name: 'L2'
coeff: 0.0004
coeff: 0.00004
# data loader for train and eval

View File

@ -41,7 +41,7 @@ Optimizer:
values: [0.1, 0.01, 0.001, 0.0001]
regularizer:
name: 'L2'
coeff: 0.0003
coeff: 0.00003
# data loader for train and eval

View File

@ -39,7 +39,7 @@ Optimizer:
values: [0.1, 0.01, 0.001, 0.0001]
regularizer:
name: 'L2'
coeff: 0.0003
coeff: 0.00003
# data loader for train and eval

View File

@ -39,7 +39,7 @@ Optimizer:
values: [0.1, 0.01, 0.001, 0.0001]
regularizer:
name: 'L2'
coeff: 0.0003
coeff: 0.00003
# data loader for train and eval

View File

@ -39,7 +39,7 @@ Optimizer:
values: [0.1, 0.01, 0.001, 0.0001]
regularizer:
name: 'L2'
coeff: 0.0003
coeff: 0.00003
# data loader for train and eval

View File

@ -39,7 +39,7 @@ Optimizer:
learning_rate: 0.045
regularizer:
name: 'L2'
coeff: 0.0004
coeff: 0.00004
# data loader for train and eval

View File

@ -37,7 +37,7 @@ Optimizer:
learning_rate: 0.045
regularizer:
name: 'L2'
coeff: 0.0003
coeff: 0.00003
# data loader for train and eval

View File

@ -37,7 +37,7 @@ Optimizer:
learning_rate: 0.045
regularizer:
name: 'L2'
coeff: 0.0003
coeff: 0.00003
# data loader for train and eval

View File

@ -37,7 +37,7 @@ Optimizer:
learning_rate: 0.045
regularizer:
name: 'L2'
coeff: 0.0004
coeff: 0.00004
# data loader for train and eval

View File

@ -37,7 +37,7 @@ Optimizer:
learning_rate: 0.045
regularizer:
name: 'L2'
coeff: 0.0004
coeff: 0.00004
# data loader for train and eval

View File

@ -37,7 +37,7 @@ Optimizer:
learning_rate: 0.045
regularizer:
name: 'L2'
coeff: 0.0004
coeff: 0.00004
# data loader for train and eval

View File

@ -0,0 +1,129 @@
# global configs
Global:
checkpoints: null
pretrained_model: null
output_dir: ./output/
device: gpu
save_interval: 1
eval_during_train: True
eval_interval: 1
epochs: 240
print_batch_step: 10
use_visualdl: False
# used for static mode and model export
image_shape: [3, 224, 224]
save_inference_dir: ./inference
# model architecture
Arch:
name: ShuffleNetV2_swish
class_num: 1000
# loss function config for traing/eval process
Loss:
Train:
- CELoss:
weight: 1.0
Eval:
- CELoss:
weight: 1.0
Optimizer:
name: Momentum
momentum: 0.9
lr:
name: Cosine
learning_rate: 0.5
warmup_epoch: 5
regularizer:
name: 'L2'
coeff: 0.00004
# data loader for train and eval
DataLoader:
Train:
dataset:
name: ImageNetDataset
image_root: ./dataset/ILSVRC2012/
cls_label_path: ./dataset/ILSVRC2012/train_list.txt
transform_ops:
- DecodeImage:
to_rgb: True
channel_first: False
- RandCropImage:
size: 224
- RandFlipImage:
flip_code: 1
- NormalizeImage:
scale: 1.0/255.0
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
sampler:
name: DistributedBatchSampler
batch_size: 256
drop_last: False
shuffle: True
loader:
num_workers: 4
use_shared_memory: True
Eval:
dataset:
name: ImageNetDataset
image_root: ./dataset/ILSVRC2012/
cls_label_path: ./dataset/ILSVRC2012/val_list.txt
transform_ops:
- DecodeImage:
to_rgb: True
channel_first: False
- ResizeImage:
resize_short: 256
- CropImage:
size: 224
- NormalizeImage:
scale: 1.0/255.0
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
sampler:
name: DistributedBatchSampler
batch_size: 64
drop_last: False
shuffle: False
loader:
num_workers: 4
use_shared_memory: True
Infer:
infer_imgs: docs/images/whl/demo.jpg
batch_size: 10
transforms:
- DecodeImage:
to_rgb: True
channel_first: False
- ResizeImage:
resize_short: 256
- 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:
PostProcess:
name: Topk
topk: 5
class_id_map_file: ppcls/utils/imagenet1k_label_list.txt
Metric:
Train:
- TopkAcc:
topk: [1, 5]
Eval:
- TopkAcc:
topk: [1, 5]

View File

@ -38,7 +38,7 @@ Optimizer:
warmup_epoch: 5
regularizer:
name: 'L2'
coeff: 0.0003
coeff: 0.00003
# data loader for train and eval

View File

@ -38,7 +38,7 @@ Optimizer:
warmup_epoch: 5
regularizer:
name: 'L2'
coeff: 0.0003
coeff: 0.00003
# data loader for train and eval

View File

@ -38,7 +38,7 @@ Optimizer:
warmup_epoch: 5
regularizer:
name: 'L2'
coeff: 0.0003
coeff: 0.00003
# data loader for train and eval

View File

@ -38,7 +38,7 @@ Optimizer:
warmup_epoch: 5
regularizer:
name: 'L2'
coeff: 0.0004
coeff: 0.00004
# data loader for train and eval

View File

@ -38,7 +38,7 @@ Optimizer:
warmup_epoch: 5
regularizer:
name: 'L2'
coeff: 0.0004
coeff: 0.00004
# data loader for train and eval

View File

@ -38,7 +38,7 @@ Optimizer:
warmup_epoch: 5
regularizer:
name: 'L2'
coeff: 0.0004
coeff: 0.00004
# data loader for train and eval

View File

@ -588,7 +588,7 @@ class Trainer(object):
if len(batch) == 3:
has_unique_id = True
batch[2] = batch[2].reshape([-1, 1]).astype("int64")
out = self.model(batch[0], batch[1])
out = self.forward(batch)
batch_feas = out["features"]
# do norm
@ -653,7 +653,7 @@ class Trainer(object):
image_file_list.append(image_file)
if len(batch_data) >= batch_size or idx == len(image_list) - 1:
batch_tensor = paddle.to_tensor(batch_data)
out = self.model(batch_tensor)
out = self.forward([batch_tensor])
if isinstance(out, list):
out = out[0]
result = postprocess_func(out, image_file_list)

View File

@ -185,7 +185,7 @@ function func_inference(){
elif [ ${use_gpu} = "True" ] || [ ${use_gpu} = "gpu" ]; then
for use_trt in ${use_trt_list[*]}; do
for precision in ${precision_list[*]}; do
if [ ${precision} = "False" ] && [ ${use_trt} = "False" ]; then
if [ ${precision} = "True" ] && [ ${use_trt} = "False" ]; then
continue
fi
if [[ ${use_trt} = "False" || ${precision} =~ "int8" ]] && [ ${_flag_quant} = "True" ]; then