赞
踩
转自AI Studio,原文链接:基于PP-ShiTu的商品识别系统 - 飞桨AI Studio
1、项目效果
2、发展概况
随着无人超市、新零售等商业模式的发展,越来越多的品牌商及商超零售企业开始引进人工智能技术,探索商品管理、成本控制、用户体验等多维度的数字化转型,转型中所涉及的货架陈列分析、智能结算、智能库存管理、智能货柜、电商平台等以图搜图的场景背后的核心技术都离不开商品识别算法。
3、痛点问题
4、解决方案
PaddleClas团队开源的图像识别PP-ShiTu技术方案,主要由主体检测、特征学习和向量检索三个模块组成,是一个实用的轻量级通用图像识别系统。基于此技术方案,商超零售企业可实现大量商品的一键式智能化识别,大大提高识别效率,节省人工及时间成本。
此外,当新品迭代更新时,PP-shitu无需重新训练模型,能够做到“即增即用”,完美解决上述痛点问题,大大提高了人工智能在商超零售行业的应用落地可能性。
PP-shitu技术方案可具体应用于例如:商品结算、库存管理等关于商品识别的商超细分场景。
In [ ]
- # 克隆 PaddleClas
- # 此代码只需要执行一次,本项目已完成克隆
- # # github仓库
- # !git clone https://github.com/PaddlePaddle/PaddleClas.git -b release/2.3
- # gitee仓库(推荐)
- # !git clone https://gitee.com/paddlepaddle/PaddleClas.git -b release/2.3
In [ ]
- # 如果需要进行持久化安装, 需要使用持久化路径, 如下方代码示例:
- # If a persistence installation is required,
- # you need to use the persistence path as the following:
- !mkdir /home/aistudio/external-libraries
- !pip install -r /home/aistudio/PaddleClas/requirements.txt
In [ ]
- # 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可:
- # Also add the following code,
- # so that every time the environment (kernel) starts,
- # just run the following code:
- import sys
- sys.path.append('/home/aistudio/external-libraries')
1、数据集介绍
目前开源的商品识别方向的数据集
2、RP2K数据集可视化
In [ ]
- # 解压数据集
- !unzip -oq /home/aistudio/data/data130337/dataset.zip -d /home/aistudio/work/
In [ ]
- # 查看文件夹架构,顺便统计文件总数量
- # !tree /home/aistudio/work/dataset/all/train
- !tree /home/aistudio/work/dataset/all/test
In [ ]
- # 解压标签数据集
- # !unzip -oq /home/aistudio/data/data67153/RP2K_rp2k_dataset.zip -d /home/aistudio/data
In [ ]
# !tree /home/aistudio/data/all/test
In [ ]
- # 数据预处理
- import os
- data_dir = 'work/dataset/all/train'
- pathlist = os.listdir(data_dir)
- ls = [int(k) for k in pathlist]
- print(max(ls))
- print(min(ls))
- print(len(ls))
- # 图像的可视化
- import matplotlib.pyplot as plt
- %matplotlib inline
- from PIL import Image
- import numpy as np
- img_dir = 'work/dataset/all/train/2383'
- img_name = '327804.jpg'
- img_path = os.path.join(img_dir, img_name)
- img = Image.open(img_path)
- img = np.array(img)
- print(img.shape)
- plt.figure(figsize=(8,8))
- plt.imshow(img)
2388 1 2388 (716, 218, 3)
<matplotlib.image.AxesImage at 0x7f091f2f29d0>
<Figure size 576x576 with 1 Axes>
PP-ShiTu是一个实用的轻量级通用图像识别系统,主要由主体检测、特征学习和向量检索三个模块组成。该系统从骨干网络选择和调整、损失函数的选择、数据增强、学习率变换策略、正则化参数选择、预训练模型使用以及模型裁剪量化8个方面,采用多种策略,对各个模块的模型进行优化,最终得到在CPU上仅0.2s即可完成10w+库的图像识别的系统。
1、主体检测
主体检测技术是目前应用非常广泛的一种检测技术,它指的是检测出图片中一个或者多个主体的坐标位置,然后将图像中的对应区域裁剪下来,进行识别,从而完成整个识别过程。主体检测是识别任务的前序步骤,可以有效提升识别精度。
考虑到商品识别实际应用场景中,需要快速准确地获得识别结果,故本项目选取适用于 CPU 或者移动端场景的轻量级主体检测模型PicoDet作为本项目主体检测部分的模型。此模型融合了ATSS、Generalized Focal Loss、余弦学习率策略、Cycle-EMA、轻量级检测 head等一系列优化算法,基于COCO train2017数据集进行大规模预训练,最终inference模型大小(MB)仅30.1MB,mAP可达40.1%,在cpu下单张图片预测耗时仅29.8ms,完美符合本项目实际落地需求,故在本项目中不对主体检测部分做适应性训练。
2、特征提取
特征提取是图像识别中的关键一环,它的作用是将输入的图片转化为固定维度的特征向量,用于后续的向量检索。好的特征需要具备相似度保持性,即在特征空间中,相似度高的图片对其特征相似度要比较高(距离比较近),相似度低的图片对,其特征相似度要比较小(距离比较远)。Deep Metric Learning用以研究如何通过深度学习的方法获得具有强表征能力的特征。
考虑到本项目的真实落地的场景中,推理速度及预测准确率是考量模型好坏的重要指标,所以本项目采用 CPU 级轻量化骨干网络 PP_LCNet_x2_5 作为骨干网络, Neck 部分选用 Linear Layer, Head 部分选用 ArcMargin,Loss 部分选用 CELoss,并结合度量学习arcmargin算法,对高相似物体的区分效果远超单一模型。在 Intel 至强 6148 处理器,PP-LCNet 的单张图像 5.39ms 的预测速度下,在 ImageNet 上 Top1 识别准确率可以达到 80.82%,准确率超越大模型 ResNet50 的模型效果,而预测速度却可以达到后者的 3 倍!PP-ShiTu 充分挖掘该网络的潜力,学习一个具有超强泛化能力的特征提取模型,同一模型可在多个数据集上同时达到较高精度。
3、向量检索
PP-ShiTu 的第三个模块是向量检索。当获得了图像特征后,我们通过计算向量距离来获得两张图像的相似度,进一步通过向量检索获取最终识别结果。这种方式最大的优点是,当增加新的品类时,不需要重新训练提取特征模型,仅需要更新检索库即可识别新的目标。为了更好地兼容(Linux, Windows, MacOS)多平台,在图像识别系统中,本项目使用 Faiss 。在此过程中,本项目选取 HNSW32 为检索算法,使得检索精度、检索速度能够取得较好的平衡,更为贴切本项目实际应用场景的使用需求。
In [ ]
- # 检测模型训练
- %cd /home/aistudio/PaddleClas
- !python tools/train.py \
- -c ./ppcls/configs/GeneralRecognition/GeneralRecognition_PPLCNet_x2_5.yaml \
- -o Arch.Backbone.pretrained=True \
- -o Arch.Head.class_num=2389 \
- -o Global.epochs=100 \
- -o Global.device=gpu \
- -o Global.checkpoints=./output_wide/RecModel/latest
In [ ]
- %cd /home/aistudio/PaddleClas
- !python tools/eval.py \
- -c ./ppcls/configs/GeneralRecognition/GeneralRecognition_PPLCNet_x2_5.yaml \
- -o Global.pretrained_model="/home/aistudio/PaddleClas/output/RecModel/best_model"
best model的统计是metric,会考虑到类内类间的差异,更好反映模型的健壮性(Best_Metric: 0.94251,观察到的最大值不太准)
评估结果展示,总共跑了三种配置,每种配置训练100个Epoch,结果展示如下:
output: recall1: 92.392, recall5: 96.010
output_new: recall1: 94.074, recall5: 97.242, (recall1最高可以达到94.249)
output_wide: recall1: 94.101, recall5: 97.283,(best metric最优)
可见,最优的模型为output_wide模型,我们之后的推理模型都用wide模型
导出推理模型
PaddlePaddle框架保存的权重文件分为两种:支持前向推理和反向梯度的训练模型 和 只支持前向推理的推理模型。二者的区别是推理模型针对推理速度和显存做了优化,裁剪了一些只在训练过程中才需要的tensor,降低显存占用,并进行了一些类似层融合,kernel选择的速度优化。因此可执行如下命令导出推理模型。
In [ ]
- # 导出推理模型
- %cd /home/aistudio/PaddleClas
- !python tools/export_model.py \
- -c ./ppcls/configs/GeneralRecognition/GeneralRecognition_PPLCNet_x2_5.yaml \
- -o Global.pretrained_model="output_wide/RecModel/best_model"
In [ ]
- # 测试代码:获取待测试图片的特征向量
- %cd /home/aistudio/PaddleClas/deploy
- !python python/predict_rec.py \
- -c configs/inference_rec.yaml \
- -o Global.rec_inference_model_dir="../inference" \
- -o Global.infer_imgs="/home/aistudio/work/dataset/test_image/wine.jpg"
1、商品识别系统的识别原理如下:
configs/build_general.yaml
文件内容:- Global:
- rec_inference_model_dir: "/home/aistudio/PaddleClas/inference"
- IndexProcess:
- index_method: "HNSW32" # supported: HNSW32, IVF, Flat
- image_root: "/home/aistudio/work/dataset/all/"
- index_dir: "/home/aistudio/work/dataset/all/index"
- data_file: "/home/aistudio/work/dataset/all/gallery_label.txt"
- index_operation: "new" # suported: "append", "remove", "new"
- delimiter: "\t"
- dist_type: "IP"
- embedding_size: 4096
执行如下代码:
In [ ]
- # 数据集没有提供gallery_label.txt
- # 读取test_list.txt,然后每一类选择三个(不足则全部选择),加入gallery_label.txt
- import os
- contents = []
- with open("/home/aistudio/work/dataset/all/test_list.txt", 'r') as fa:
- contents = fa.readlines()
-
- def warp(s):
- ls = s.split()[0:2]
- new_s = "\t".join(ls)
- return new_s
-
- contents = list(map(warp, contents))
-
- import shutil
- os.chdir('/home/aistudio/work/dataset/all/')
- with open("/home/aistudio/work/dataset/all/gallery_label.txt", 'w') as fb:
- cnt = 0
- prev = ''
- for line in contents:
- if prev == '' or line.split('\t')[-1] != prev:
- cnt = 0
- if cnt < 3:
- path = line.split('\t')[0]
- name = path.split('/')[-1]
- shutil.copy(path, 'gallery/' + name)
- prev = line.split('\t')[-1]
- fb.write('gallery/' + name + '\t' + prev + '\n')
- cnt += 1
In [ ]
- # 首先建立索引库
- %cd /home/aistudio/PaddleClas/deploy
- !python3 python/build_gallery.py \
- -c configs/build_general.yaml \
- -o IndexProcess.data_file="/home/aistudio/work/dataset/all/gallery_label.txt" \
- -o IndexProcess.index_dir="/home/aistudio/work/dataset/all/index"
/home/aistudio/PaddleClas/deploy 2022-05-17 11:33:33 INFO: =========================================================== == PaddleClas is powered by PaddlePaddle ! == =========================================================== == == == For more info please go to the following website. == == == == https://github.com/PaddlePaddle/PaddleClas == =========================================================== 2022-05-17 11:33:33 INFO: Global : 2022-05-17 11:33:33 INFO: batch_size : 32 2022-05-17 11:33:33 INFO: cpu_num_threads : 10 2022-05-17 11:33:33 INFO: enable_benchmark : True 2022-05-17 11:33:33 INFO: enable_mkldnn : True 2022-05-17 11:33:33 INFO: enable_profile : False 2022-05-17 11:33:33 INFO: gpu_mem : 8000 2022-05-17 11:33:33 INFO: ir_optim : True 2022-05-17 11:33:33 INFO: rec_inference_model_dir : /home/aistudio/PaddleClas/inference 2022-05-17 11:33:33 INFO: use_fp16 : False 2022-05-17 11:33:33 INFO: use_gpu : True 2022-05-17 11:33:33 INFO: use_tensorrt : False 2022-05-17 11:33:33 INFO: IndexProcess : 2022-05-17 11:33:33 INFO: data_file : /home/aistudio/work/dataset/all/gallery_label.txt 2022-05-17 11:33:33 INFO: delimiter : 2022-05-17 11:33:33 INFO: dist_type : IP 2022-05-17 11:33:33 INFO: embedding_size : 4096 2022-05-17 11:33:33 INFO: image_root : /home/aistudio/work/dataset/all/ 2022-05-17 11:33:33 INFO: index_dir : /home/aistudio/work/dataset/all/index 2022-05-17 11:33:33 INFO: index_method : HNSW32 2022-05-17 11:33:33 INFO: index_operation : new 2022-05-17 11:33:33 INFO: RecPostProcess : None 2022-05-17 11:33:33 INFO: RecPreProcess : 2022-05-17 11:33:33 INFO: transform_ops : 2022-05-17 11:33:33 INFO: ResizeImage : 2022-05-17 11:33:33 INFO: size : 224 2022-05-17 11:33:33 INFO: NormalizeImage : 2022-05-17 11:33:33 INFO: mean : [0.485, 0.456, 0.406] 2022-05-17 11:33:33 INFO: order : 2022-05-17 11:33:33 INFO: scale : 0.00392157 2022-05-17 11:33:33 INFO: std : [0.229, 0.224, 0.225] 2022-05-17 11:33:33 INFO: ToCHWImage : None 100%|██████████████████████████████████████| 5850/5850 [00:20<00:00, 281.66it/s] 2022-05-17 11:33:55 WARNING: The HNSW32 method dose not support 'remove' operation
运行如下命令,下载通用检测inference
模型并解压:
下载完成后/home/aistudio/PaddleClas/deploy/文件夹下建立了一个models的子文件夹,里面是主体检测模型解压完成的文件夹,文件夹里包含四个文件,其中三个是推理模型的相关权重参数,另一个是推理用的配置文件。
In [ ]
- %cd /home/aistudio/PaddleClas/deploy/
- %mkdir models
- %cd models
- # 下载通用检测 inference 模型并解压
- # 上面那里保存的是特征提取的backbone的推理模型,这里是主体检测的推理模型Picodet
- !wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/models/inference/picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer.tar && tar -xf picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer.tar
修改推理文件configs/inference_general.yaml
内容:
- Global:
- det_inference_model_dir: "./models/picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer"
- rec_inference_model_dir: "/home/aistudio/PaddleClas/inference"
- rec_nms_thresold: 0.05
- IndexProcess:
- index_method: "HNSW32" # supported: HNSW32, IVF, Flat
- image_root: "/home/aistudio/dataset/all/gallery/"
- index_dir: "/home/aistudio/dataset/all/index"
- data_file: "/home/aistudio/work/dataset/all/gallery_label.txt"
- index_operation: "new" # suported: "append", "remove", "new"
- delimiter: "\t"
- dist_type: "IP"
- embedding_size: 4096
- batch_size: 32
- return_k: 5
- score_thres: 0.5
注意,配置文件中的infer_imgs字段不需要修改,我们在推理的时候使用命令行传入需要推理的图片路径即可
1、第一种测试情况为待测试图片为索引库中已经存在的图片
In [ ]
- # 基于索引库的图像识别
- %cd /home/aistudio/PaddleClas/deploy
- %pwd
- !python python/predict_system.py \
- -c configs/inference_general.yaml \
- -o Global.infer_imgs="/home/aistudio/work/dataset/test_image/wine.jpg" \
- -o IndexProcess.index_dir="/home/aistudio/work/dataset/all/index"
其中 bbox 表示检测出的主体所在位置,rec_docs 表示索引库中与检测框最为相似的类别,rec_scores 表示对应的置信度。
检测的可视化结果也保存在 output 文件夹下,对于本张图像,识别结果可视化如下所示:
2. 若商品为原索引库里没有的商品:
对图像 /home/aistudio/dataset/test_image/recognition_2.jpg
进行识别, 待检索图像如下所示。
运行如下识别命令:
In [ ]
- # 识别
- %cd /home/aistudio/PaddleClas/deploy
- !python python/predict_system.py \
- -c configs/inference_general.yaml \
- -o Global.infer_imgs="/home/aistudio/work/dataset/test_image/xiaodu.jpg" \
- -o IndexProcess.index_dir="/home/aistudio/work/dataset/all/index"
由于默认的索引库中不包含对应的索引信息,所以这里的识别结果有误,此时我们可以通过构建新的索引库的方式,完成未知类别的图像识别。
当索引库中的图像无法覆盖我们实际识别的场景时,即在预测未知类别的图像时,只需要将对应类别的相似图像添加到索引库中,从而完成对未知类别的图像识别,这一过程是不需要重新训练的。
准备新的数据与标签
首先需要将与待检索图像相似的图像列表拷贝到索引库原始图像的文件夹。这里将所有的底库图像数据都放在文件夹 /home/aistudio/dataset/all/gallery/ 中。
然后需要编辑记录了图像路径和标签信息的文本文件,这里 PaddleClas 将更正后的标签信息文件放在了 /home/aistudio/dataset/all/gallery_update.txt 文件中。可以与原来的 /home/aistudio/dataset/all/gallery_label.txt 标签文件进行对比,添加了小度充电宝和韩国进口火山泥的索引图像。
每一行的文本中,第一个字段表示图像的相对路径,第二个字段表示图像对应的标签信息,中间用 \t 键分隔开
In [ ]
- # 使用下面的命令建立新的 index 索引,加速识别后的检索过程
- %cd /home/aistudio/PaddleClas/deploy/
- %pwd
- !python python/build_gallery.py \
- -c configs/build_general.yaml \
- -o IndexProcess.data_file="/home/aistudio/work/dataset/all/gallery_update.txt" \
- -o IndexProcess.index_dir="/home/aistudio/work/dataset/all/index_update"
/home/aistudio/PaddleClas/deploy 2022-05-17 11:42:10 INFO: =========================================================== == PaddleClas is powered by PaddlePaddle ! == =========================================================== == == == For more info please go to the following website. == == == == https://github.com/PaddlePaddle/PaddleClas == =========================================================== 2022-05-17 11:42:10 INFO: Global : 2022-05-17 11:42:10 INFO: batch_size : 32 2022-05-17 11:42:10 INFO: cpu_num_threads : 10 2022-05-17 11:42:10 INFO: enable_benchmark : True 2022-05-17 11:42:10 INFO: enable_mkldnn : True 2022-05-17 11:42:10 INFO: enable_profile : False 2022-05-17 11:42:10 INFO: gpu_mem : 8000 2022-05-17 11:42:10 INFO: ir_optim : True 2022-05-17 11:42:10 INFO: rec_inference_model_dir : /home/aistudio/PaddleClas/inference 2022-05-17 11:42:10 INFO: use_fp16 : False 2022-05-17 11:42:10 INFO: use_gpu : True 2022-05-17 11:42:10 INFO: use_tensorrt : False 2022-05-17 11:42:10 INFO: IndexProcess : 2022-05-17 11:42:10 INFO: data_file : /home/aistudio/work/dataset/all/gallery_update.txt 2022-05-17 11:42:10 INFO: delimiter : 2022-05-17 11:42:10 INFO: dist_type : IP 2022-05-17 11:42:10 INFO: embedding_size : 4096 2022-05-17 11:42:10 INFO: image_root : /home/aistudio/work/dataset/all/ 2022-05-17 11:42:10 INFO: index_dir : /home/aistudio/work/dataset/all/index_update 2022-05-17 11:42:10 INFO: index_method : HNSW32 2022-05-17 11:42:10 INFO: index_operation : new 2022-05-17 11:42:10 INFO: RecPostProcess : None 2022-05-17 11:42:10 INFO: RecPreProcess : 2022-05-17 11:42:10 INFO: transform_ops : 2022-05-17 11:42:10 INFO: ResizeImage : 2022-05-17 11:42:10 INFO: size : 224 2022-05-17 11:42:10 INFO: NormalizeImage : 2022-05-17 11:42:10 INFO: mean : [0.485, 0.456, 0.406] 2022-05-17 11:42:10 INFO: order : 2022-05-17 11:42:10 INFO: scale : 0.00392157 2022-05-17 11:42:10 INFO: std : [0.229, 0.224, 0.225] 2022-05-17 11:42:10 INFO: ToCHWImage : None 100%|██████████████████████████████████████| 5852/5852 [00:21<00:00, 271.76it/s] 2022-05-17 11:42:33 WARNING: The HNSW32 method dose not support 'remove' operation
最终新的索引信息保存在文件夹 /home/aistudio/dataset/all/index_update
中。
使用新的索引库,对上述图像进行识别,运行命令如下:
In [ ]
- %cd /home/aistudio/PaddleClas/deploy/
- !python python/predict_system.py \
- -c configs/inference_general.yaml \
- -o Global.infer_imgs="/home/aistudio/work/dataset/test_image/xiaodu.jpg" \
- -o IndexProcess.index_dir="/home/aistudio/work/dataset/all/index_update"
/home/aistudio/PaddleClas/deploy 2022-05-17 11:43:18 INFO: =========================================================== == PaddleClas is powered by PaddlePaddle ! == =========================================================== == == == For more info please go to the following website. == == == == https://github.com/PaddlePaddle/PaddleClas == =========================================================== 2022-05-17 11:43:18 INFO: DetPostProcess : 2022-05-17 11:43:18 INFO: DetPreProcess : 2022-05-17 11:43:18 INFO: transform_ops : 2022-05-17 11:43:18 INFO: DetResize : 2022-05-17 11:43:18 INFO: interp : 2 2022-05-17 11:43:18 INFO: keep_ratio : False 2022-05-17 11:43:18 INFO: target_size : [640, 640] 2022-05-17 11:43:18 INFO: DetNormalizeImage : 2022-05-17 11:43:18 INFO: is_scale : True 2022-05-17 11:43:18 INFO: mean : [0.485, 0.456, 0.406] 2022-05-17 11:43:18 INFO: std : [0.229, 0.224, 0.225] 2022-05-17 11:43:18 INFO: DetPermute : 2022-05-17 11:43:18 INFO: Global : 2022-05-17 11:43:18 INFO: batch_size : 1 2022-05-17 11:43:18 INFO: cpu_num_threads : 10 2022-05-17 11:43:18 INFO: det_inference_model_dir : ./models/picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer 2022-05-17 11:43:18 INFO: enable_benchmark : True 2022-05-17 11:43:18 INFO: enable_mkldnn : True 2022-05-17 11:43:18 INFO: enable_profile : False 2022-05-17 11:43:18 INFO: gpu_mem : 8000 2022-05-17 11:43:18 INFO: image_shape : [3, 640, 640] 2022-05-17 11:43:18 INFO: infer_imgs : /home/aistudio/work/dataset/test_image/xiaodu.jpg 2022-05-17 11:43:18 INFO: ir_optim : True 2022-05-17 11:43:18 INFO: labe_list : ['foreground'] 2022-05-17 11:43:18 INFO: max_det_results : 5 2022-05-17 11:43:18 INFO: rec_inference_model_dir : /home/aistudio/PaddleClas/inference 2022-05-17 11:43:18 INFO: rec_nms_thresold : 0.05 2022-05-17 11:43:18 INFO: threshold : 0.2 2022-05-17 11:43:18 INFO: use_fp16 : False 2022-05-17 11:43:18 INFO: use_gpu : True 2022-05-17 11:43:18 INFO: use_tensorrt : False 2022-05-17 11:43:18 INFO: IndexProcess : 2022-05-17 11:43:18 INFO: batch_size : 32 2022-05-17 11:43:18 INFO: data_file : /home/aistudio/work/dataset/all/gallery_label.txt 2022-05-17 11:43:18 INFO: delimiter : 2022-05-17 11:43:18 INFO: dist_type : IP 2022-05-17 11:43:18 INFO: embedding_size : 4096 2022-05-17 11:43:18 INFO: image_root : /home/aistudio/dataset/all/gallery/ 2022-05-17 11:43:18 INFO: index_dir : /home/aistudio/work/dataset/all/index_update 2022-05-17 11:43:18 INFO: index_method : HNSW32 2022-05-17 11:43:18 INFO: index_operation : new 2022-05-17 11:43:18 INFO: return_k : 5 2022-05-17 11:43:18 INFO: score_thres : 0.5 2022-05-17 11:43:18 INFO: RecPostProcess : None 2022-05-17 11:43:18 INFO: RecPreProcess : 2022-05-17 11:43:18 INFO: transform_ops : 2022-05-17 11:43:18 INFO: ResizeImage : 2022-05-17 11:43:18 INFO: size : 224 2022-05-17 11:43:18 INFO: NormalizeImage : 2022-05-17 11:43:18 INFO: mean : [0.485, 0.456, 0.406] 2022-05-17 11:43:18 INFO: order : 2022-05-17 11:43:18 INFO: scale : 0.00392157 2022-05-17 11:43:18 INFO: std : [0.229, 0.224, 0.225] 2022-05-17 11:43:18 INFO: ToCHWImage : None Inference: 27.196168899536133 ms per batch image [{'bbox': [522, 43, 708, 413], 'rec_docs': '韩国进口火山泥', 'rec_scores': 0.67161095}, {'bbox': [140, 86, 302, 400], 'rec_docs': '小度充电宝', 'rec_scores': 0.5900027}]
由测试效果图可知,模型对于未参与训练的商品及多个商品均有较好的识别效果,并且上图是鑫哥的PP-ShiTu图像分类项目中的识别结果,下图是本项目模型的识别结果,精度有所提高,说明上大数据集RP2K进行训练还是更有效的。
1、检测模型调优
PP-ShiTu
中检测模型采用的 PicoDet
算法,在使用官方模型后,如果不满足精度需求,则可以参考此部分文档,进行模型调优
2、识别模型调优
因为要对模型进行训练,所以参照数据准备部分描述收集自己的数据集。值得注意的是,此部分需要准备大量的数据,以保证识别模型效果。
RandomErasing
增强方法。backbone
,一般来说,越大的模型,特征提取能力更强。Metric Learning
方法。不同的Metric Learning
方法,对不同的数据集效果可能不太一样,建议尝试其他Loss
模型训练完成后,参照系统测试进行检索库更新。同时,对整个pipeline进行测试,如果精度不达预期,则重复此步骤。
下一步是部署,但是限于时间原因,目前该项目的前端尚未搭建完成,最近杂事比较多,等有时间了会将其进行部署(Web或者安卓都可以考虑),因为目前看来,推理速度是15FPS左右,可以在移动端尝试。
因此,下一步将模型部署换成了视频流的实时监测,思路也比较简单,感兴趣的可以详细查看下方的代码。
In [ ]
- # 导入依赖库
- import paddle
- import cv2
- import os
- import numpy as np
1、视频流检测的主要步骤:
2、不足之处:
3、改进方案:
In [ ]
- import cv2
- import numpy as np
- from PIL import Image, ImageDraw
- import os
- def CutVideo2Image(video_path, img_path):
- #将视频输出为图像
- #video_path为输入视频文件路径
- #img_path为输出图像文件夹路径
- cap = cv2.VideoCapture(video_path)
- index = 0
- while(True):
- ret,frame = cap.read()
- if ret:
- cv2.imwrite(img_path+'/%d.jpg'%index, frame)
- index += 1
- else:
- break
- cap.release()
-
- def CombVideo(in_path, out_path, size):
- #将图片合成视频
- #in_path为输入图像文件夹路径
- #out_path为输出视频文件路径
- fourcc = cv2.VideoWriter_fourcc(*'XVID')
- out = cv2.VideoWriter(out_path,fourcc, fps=15.0, frameSize=size)
- files = os.listdir(in_path)
- for path in files:
- if path[-3:] != 'jpg':
- files.remove(path)
- for i in range(len(files)):
- img = cv2.imread(in_path + '/%d.jpg' % i)
- img = cv2.resize(img, size)
- out.write(img)
- out.release()
-
- def Iou(bbox1,bbox2):
- #计算Iou
- #bbox1,bbox为xyxy数据
- area1 = (bbox1[2]-bbox1[0])*(bbox1[3]-bbox1[1])
- area2 = (bbox2[2]-bbox2[0])*(bbox2[3]-bbox2[1])
- w = min(bbox1[3],bbox2[3])-max(bbox1[1],bbox2[1])
- h = min(bbox1[2],bbox2[2])-max(bbox1[0],bbox2[0])
- if w<=0 or h<=0:
- return 0
- area_mid = w*h
- return area_mid/(area1+area2-area_mid)
In [ ]
- # 加载推理模型
- from paddle.inference import Config
- from paddle.inference import create_predictor
- def init_predictor():
- model_file = 'PaddleClas/deploy/models/picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer/inference.pdmodel'
- params_file = 'PaddleClas/deploy/models/picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer/inference.pdiparams'
- config = Config(model_file, params_file)
-
- config.enable_memory_optim()
- config.enable_use_gpu(1000, 0)
-
- predictor = create_predictor(config)
- return predictor
-
-
- def run(predictor, img):
- input_names = predictor.get_input_names()
- for i, name in enumerate(input_names):
- input_tensor = predictor.get_input_handle(name)
- input_tensor.reshape(img[i].shape)
- input_tensor.copy_from_cpu(img[i].copy())
-
- predictor.run()
-
- results = []
- output_names = predictor.get_output_names()
- for i, name in enumerate(output_names):
- output_tensor = predictor.get_output_handle(name)
- output_data = output_tensor.copy_to_cpu()
- results.append(output_data)
- return results
In [ ]
- def resize(img, target_size):
- """resize to target size"""
- if not isinstance(img, np.ndarray):
- raise TypeError('image type is not numpy.')
- im_shape = img.shape
- im_size_min = np.min(im_shape[0:2])
- im_size_max = np.max(im_shape[0:2])
- im_scale_x = float(target_size) / float(im_shape[1])
- im_scale_y = float(target_size) / float(im_shape[0])
- img = cv2.resize(img, None, None, fx=im_scale_x, fy=im_scale_y)
- return img
-
-
- def normalize(img, mean, std):
- img = img / 255.0
- mean = np.array(mean)[np.newaxis, np.newaxis, :]
- std = np.array(std)[np.newaxis, np.newaxis, :]
- img -= mean
- img /= std
- return img
-
-
- def preprocess(img, img_size):
- mean = [0.485, 0.456, 0.406]
- std = [0.229, 0.224, 0.225]
- img = resize(img, img_size)
- img = img[:, :, ::-1].astype('float32') # bgr -> rgb
- img = normalize(img, mean, std)
- img = img.transpose((2, 0, 1)) # hwc -> chw
- return img[np.newaxis, :]
-
-
- def draw_bbox(img, result, threshold=0.5, save_name='res.jpg'):
- """draw bbox"""
- draw = ImageDraw.Draw(img)
- for res in result:
- cat_id, score, bbox = res[0], res[1], res[2:]
- if score < threshold:
- continue
- xmin, ymin, xmax, ymax = bbox
- draw.line([(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin),
- (xmin, ymin)],
- width=2,
- fill=(255, 0, 0))
- print('category id is {}, bbox is {}'.format(cat_id, bbox))
- img.save(save_name, quality=95)
In [ ]
- def Solve(img_name, save_img_name):
- # img_name = 'kite.jpg'
- # save_img_name = 'res.jpg'
- im_size = 608
- pred = init_predictor()
- img = cv2.imread(img_name)
- data = preprocess(img, im_size)
- scale_factor = np.array([im_size * 1. / img.shape[0], im_size * 1. / img.shape[1]]).reshape((1, 2)).astype(np.float32)
- im_shape = np.array([im_size, im_size]).reshape((1, 2)).astype(np.float32)
- result = run(pred, [im_shape, data, scale_factor])
- img = Image.open(img_name).convert('RGB')
- draw_bbox(img, result[0], save_name=save_img_name)
-
- def GetItem(in_path, out_path):
- # 商品检测
- # in_path为输入图像文件夹的路径
- # out_path为输出图像文件夹的路径,并为商品标注检测框和进行计数
- files = os.listdir(in_path)
- for i in range(len(files)-1):
- #文件中的每张图片
- Solve(in_path +'/%d.jpg' % i, out_path +'/%d.jpg' % i)
-
- # CombVideo(out_path, out_path+'/video.mp4', (608, 608))
以下是测试代码
In [ ]
- # 视频转图片
- CutVideo2Image('work/dataset/det.mp4', 'work/dataset/video_to_imgs')
- # 图片处理
- # GetItem('work/dataset/video_to_imgs', 'work/dataset/imgs_to_video')
In [15]
- # 基于索引库的图像识别
- %cd /home/aistudio/PaddleClas/deploy
- %pwd
- !python python/predict_system.py \
- -c configs/inference_general.yaml \
- -o Global.infer_imgs="/home/aistudio/work/dataset/video_to_imgs" \
- -o IndexProcess.index_dir="/home/aistudio/work/dataset/all/index_update"
In [21]
- # 图片转视频
- CombVideo('./output', './video.avi', (1514, 848))
- # video_capture = cv2.VideoCapture('work/dataset'+'/video.avi')
- #video_capture = cv2.VideoCapture(1)
- #video_capture = cv2.VideoCapture(0)
- # 其中0表示打开内置摄像头,1表示打开外接摄像头
- # if video_capture.isOpened(): # VideoCaputre对象是否成功打开
- # print('打开摄像头或者视频成功')
- # readVideo_flag = True
- # else:
- # print('打开摄像头或者视频失败')
- # readVideo_flag = False
- # while readVideo_flag:
- # ret, frame = video_capture.read()
- # if ret != True:
- # break
- # print("下面在notebook环境下无法展示")
- # # cv2.imshow('frame',frame)
- # video_capture.release()
本次项目我是第一次接触PP-ShiTu图像识别系统,个人感觉非常好用,各种模型的配置文件都已经写好了,比自己从头搭建甚至说去找其他的开源代码要方便的多。
在模型调优上也比较方便,根据自己的数据集选择合适的模型即可,可以对其宽度进行适当加宽,但是学习率策略、数据增强、EMA和weight decay等都保持默认是可以达到最好的效果的,说明PaddleCls提供了高质量的配置文件,大大减轻了我们的调优负担。
感谢导师郑博培大佬的指导,受益匪浅!
团队介绍:
深藏Blue队
导师:郑博培 北京联合大学 机器人学院 自动化专业 2018级 本科生 百度飞桨开发者技术专家 PPDE 中国科学院自动化研究所复杂系统管理与控制国家重点实验室实习生 阿里云人工智能、DevOps助理工程师
队长:赵祎安 大连理工大学百度飞桨领航团团长 计算机科学与技术专业 2019级 本科生
队员:杜恒辉、高兴、申晨 大连理工大学 计算机科学与技术专业 2019级 本科生
请点击此处查看本环境基本用法.
Please click here for more detailed instructions.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。