前言
本次分享将带领大家从0到1完成一个图像分类任务的模型训练评估和推理部署全流程,项目将采用以PaddleClas为核心的飞浆深度学习套装进行开发,并总结开发过程中踩过的一些坑,希望对有类似项目需求的同学提供一点帮助。
项目背景和目标
背景:
- 图像分类是计算机视觉的基础,也是其他计算机复杂任务的基础。本次选用的案例来自智慧农业,实现对不同质量桃子的自动分类,从而减轻人工挑拣的负担。
目标:
- 掌握如何基于paddlepaddle深度学习框架完成一个图像分类任务;
- 掌握如何完成模型的训练、评估、预测和部署等深度学习工作过程;
百度AI Studio平台
本次实验将采用AI Studio实训平台中的免费GPU资源,在平台注册账号后,点击创建项目-选择NoteBook任务,然后添加数据集,如下图所示,完成项目创建。启动环境可以自行选择CPU资源 or GPU资源,创建任务每天有8点免费算力,推荐大家使用GPU资源进行模型训练,这样会大幅减少模型训练时长。
数据集介绍
本次实验使用的数据集是四个种类桃子,这些桃子被分在四个文件夹中,每一个文件夹的名字就对应着一类桃子。
观察发现,这些桃子基本是按照大小、颜色来划分的,本次实验任务就是通过飞浆提供的套件完成一个图像分类任务。
飞浆深度学习开发框架介绍
PaddlePaddle百度提供的开源深度学习框架,其中文名是“飞桨”,致力于为开发者和企业提供最好的深度学习研发体验,国产框架中绝对的榜一大哥!其核心优势是生态完善,目前集成了各种开发套件,覆盖了数据处理、模型训练、模型验证、模型部署等各个阶段的工具。下面简要介绍一下本项目用到的几个核心组件:
- PaddleClas:一个图像识别和图像分类任务的工具集,集成了主流和百度自研的视觉模型和模型训练测试API。
- PaddleServing:将模型部署成一个在线预测服务的库,支持服务端和客户端之间的高并发和高效通信。
- PaddleLite:将模型转换成可以端侧推理的库,比如将模型部署到手机端进行推理。
从零开始开发
PaddleClas完成模型训练
安装PaddleClas
在项目中打开终端,然后运行如下命令:
# (可选)最好在虚拟环境中安装,环境会持久保存在项目中 pip install virtualenv # 安装虚拟环境管理包 virtualenv --python=python3.7 --system venv # 新建虚拟环境 source venv/bin/activate # 切换到新建的虚拟环境 # 安装paddlepaddle,根据云端环境选择cpu版本和gpu版本 pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple pip install paddlepaddle-gpu -i https://mirror.baidu.com/pypi/simple # 克隆PaddleClas仓库 git clone https://gitee.com/paddlepaddle/PaddleClas.git # 安装其他依赖 cd PaddleClas/ pip install --upgrade -r requirements.txt -i https://mirror.baidu.com/pypi/simple # 编译安装paddleclas python setup.py install
数据准备
我们需要制作符合PaddleClas框架要求的数据集格式:参考github.com,格式要求如下:
PaddleClas使用 txt 格式文件指定训练集和测试集,以 ImageNet1k 数据集为例,其中 train_list.txt 和 val_list.txt 的格式形如: # 每一行采用"空格"分隔图像路径与标注 # 下面是 train_list.txt 中的格式样例 train/n01440764/n01440764_10026.JPEG 0 ... # 下面是 val_list.txt 中的格式样例 val/ILSVRC2012_val_00000001.JPEG 65 ...
为此我们需要将桃子分类数据集制作上如上的格式:
# 首先将data目录下的数据解压到PaddleClas/dataset目录下 unzip /home/aistudio/data/data103593/data.zip -d /home/aistudio/PaddleClas/dataset/peach_data cd dataset/peach_data # 编写generate_dataset.py python generate_dataset.py # 生成指定格式的train_list.txt val_list.txt test_list.txt cd ../.. # 返回PaddleClas主目录
其中generate_dataset.py中的代码如下:
import os train_dir = 'train' test_dir = 'test' class_names = os.listdir(train_dir) id2names = {} for i, cls in enumerate(class_names): id2names[cls] = i # 制作标签对应关系 with open('label_list.txt', 'w') as f: f.writelines(f'{id} {name}\n' for name, id in id2names.items()) # 制作训练集和验证集 traindata_list = [] valdata_list = [] for name in class_names: class_images = os.listdir(os.path.join(train_dir, name)) for i, img in enumerate(class_images): label = id2names[name] if i%8 == 0: valdata_list.append(f'{train_dir}/{name}/{img} {label}') else: traindata_list.append(f'{train_dir}/{name}/{img} {label}') with open('train_list.txt', 'w') as f: f.writelines(f'{data}\n' for data in traindata_list) with open('val_list.txt', 'w') as f: f.writelines(f'{data}\n' for data in valdata_list) # 制作测试集 testdata_list = [] for name in class_names: class_images = os.listdir(os.path.join(train_dir, name)) for i, img in enumerate(class_images): label = id2names[name] testdata_list.append(f'{test_dir}/{name}/{img} {label}') with open('test_list.txt', 'w') as f: f.writelines(f'{data}\n' for data in testdata_list)
如上,我们便完成了数据的准备工作,接下来将选用一个model完成模型在该数据集上的训练。
模型训练和评估:
这里我们以选用百度自研的PP-LCNetV2为例,有关该模型的介绍可参考官方文档。
- 下载预训练权重:让模型参数有个好的初始化
wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/legendary_models/PPLCNetV2_base_ssld_pretrained.pdparams mv PPLCNetV2_base_ssld_pretrained.pdparams output/ # 移到output文件夹
- 修改配置文件:参考ppcls/configs/ImageNet/PPLCNetV2/PPLCNetV2_base.yaml
mkdir ppcls/configs/peach # 复制一份配置文件并根据数据集对应修改 cp ppcls/configs/ImageNet/PPLCNetV2/PPLCNetV2_base.yaml ppcls/configs/peach/ # 需要修改的地方如下 pretrained_model: ./output/PPLCNetV2_base_ssld_pretrained class_num: 4 Train: dataset: name: MultiScaleDataset image_root: ./dataset/peach_data/ cls_label_path: ./dataset/peach_data/train_list.txt Eval: dataset: name: ImageNetDataset image_root: ./dataset/peach_data/ cls_label_path: ./dataset/peach_data/val_list.txt PostProcess: name: Topk topk: 1 class_id_map_file: ./dataset/peach_data/label_list.txt
- 开启训练
# 这里需要使用云端GPU环境,cpu环境因为只有2core,训练跑不起来 python tools/train.py -c ppcls/configs/peach/PPLCNetV2_base.yaml
一般2-3个epoch就会有不错的效果。
- 模型评估
-o Global.pretrained_model 指定推理的权重位置
python tools/eval.py -c ppcls/configs/peach/PPLCNetV2_base.yaml -o Global.pretrained_model=output/PPLCNetV2_base/best_model
- 模型预测
-o Infer.infer_imgs指定预测的图片位置
python tools/infer.py -c ppcls/configs/peach/PPLCNetV2_base.yaml -o Global.pretrained_model=output/PPLCNetV2_base/best_model -o Infer.infer_imgs=./dataset/peach_data/test/M2/1800.png
模型推理部署
0 推理模型准备
其目的是为了得到用于inference的模型文件,最终存放位置由配置文件的Global.save_inference_dir指定
python tools/export_model.py -c ppcls/configs/peach/PPLCNetV2_base.yaml -o Global.pretrained_model=output/PPLCNetV2_base/best_model # 在./deploy/models/PPLCNetV2_base_infer文件下得到三个文件 - inference.pdiparams - inference.pdiparams.info - inference.pdmodel
1 基于python预测引擎推理
测试一下上述得到的用于inference的模型有没有问题
cd deploy # 复制一份inference_cls.yaml到inference_cls_peach.yaml并做相应修改,针对我们的任务需要修改的地方如下: infer_imgs: "../dataset/peach_data/test/R0/0.png" inference_model_dir: "./models/PPLCNetV2_base_infer" class_id_map_file: "../dataset/peach_data/label_list.txt" # 单张图像推理,默认使用gpu python python/predict_cls.py -c configs/inference_cls.yaml # 文件夹中所有图像推理,指定文件夹路径 python python/predict_cls.py -c configs/inference_cls_peach.yaml -o Global.infer_imgs=../dataset/peach_data/test/R0
2 服务化部署
这个部分的目的是将我们的模型部署成一个服务,客户端就可以通过http或rpc进行,飞浆已对上述需求所需要的功能实现进行了封装,细节可参考官方文档。具体执行命令如下:
# 第一步:安装必要的包 pip install paddle-serving-client==0.7.0 pip install paddle-serving-app==0.7.0 # 若为CPU部署环境: pip install paddle-serving-server==0.7.0 # 若为GPU部署环境: pip install paddle-serving-server-gpu==0.7.0.post102 # 第二步:模型转换成server需要的文件 python -m paddle_serving_client.convert --dirname ../models/PPLCNetV2_base_infer/ --model_filename inference.pdmodel --params_filename inference.pdiparams ## 运行完会在当前目录下生成两个文件夹,serving_server和serving_client # 第三步:准备配置文件 cd paddleserving/ ## 修改classification_web_service.py中依赖的配置文件config.yml和imagenet.label ## 其中config.yml中需要指定model_config: serving_server,也即我们在第二步生成的serving_server文件夹 ## 其中imagenet.label是ImageNet的标签文件,需要修改成我们数据集的标签,可以copy一份并命名为peach.label,并将4个标签填入 ## 修改classification_web_service.py中preprocess函数中{"inputs": input_imgs}=>{"x": input_imgs} ## 注意这里的"x"是因为需要和我们模型输入的名称对应,可查看serving_server/serving_server_conf.prototxt ## 修改serving_client/serving_client_conf.prototxt和serving_server/serving_server_conf.prototxt中fetch_var的alias_name,具体而言: feed_var { name: "x" alias_name: "x" is_lod_tensor: false feed_type: 1 shape: 3 shape: 224 shape: 224 } fetch_var { name: "softmax_1.tmp_0" alias_name: "prediction" is_lod_tensor: false fetch_type: 1 shape: 4 } # 第四步:启动服务 # 启动服务并放到后台运行,运行日志保存在 log.txt python classification_web_service.py &>log.txt & # 第五步:客户端调用(发送请求) python pipeline_http_client.py # http请求 python pipeline_rpc_client.py # rpc请求
3 端侧部署
这个部分的目的是将我们的模型部署到移动端(比如手机),这样就不用依赖云端服务器来进行推理了,飞浆已对上述需求所需要的功能实现进行了封装,主要体现在PaddleLite这个组件上,细节可参考官方文档。端侧部署相对稍微复杂一些,主要可以分为以下几个步骤进行:
3.1 模型优化
考虑到端侧对推理耗时要求比较高,故需要采用paddlelite对inference模型做进一步优化
# 安装最新版的paddlelite==2.12, 2.10转换pplcnet时会报错-Check failed: it != attrs().end(): No attributes called fix_seed found for dropout Aborted (core dumped) pip install paddlelite==2.12 # 模型转换 cd PaddleClas/deploy paddle_lite_opt --model_file=models/PPLCNetV2_base_infer/inference.pdmodel --param_file=models/PPLCNetV2_base_infer/inference.pdiparams --optimize_out=models/pplcnet #上述代码会在models/下生成pplcnet.nb文件
3.2 执行编译
这一步会得到手机端的可执行文件clas_system,下面以华为Mate30为例,其cpu是armv8架构,如果选用其他手机,需要查看其处理器架构是armv8还是armv7。
cd PaddleClas/deploy/lite/ # 克隆 Autolog 代码库,以便获取自动化日志 git clone https://github.com/LDOUBLEV/AutoLog.git # 如果国内下载不了,加上镜像https://mirror.ghproxy.com/ git clone https://mirror.ghproxy.com/https://github.com/LDOUBLEV/AutoLog.git # 下载 linux-x86_64 版本的 Android NDK, 并添加系统环境变量 wget https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip unzip android-ndk-r17c-linux-x86_64.zip export NDK_ROOT=/home/aistudio/android-ndk-r17c # 注意路径 # 下载paddlelite的交叉编译库-注意这里的版本2.12要和上面的paddlelite==2.12对应上 wget https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.12/inference_lite_lib.android.armv8.clang.c++_static.with_extra.with_cv.tar.gz tar -xf inference_lite_lib.android.armv8.clang.c++_static.with_extra.with_cv.tar.gz # 修改makefile,指定LITE_ROOT=./inference_lite_lib.android.armv8.clang.c++_static.with_extra.with_cv # 执行编译命令 make ## 编译成功后,会在当前目录生成 clas_system 可执行文件,该文件用于手机端推理
3.3 和手机联调
将可执行文件、模型文件和测试图片推送到手机上,进行联调。
# 第一步:windows安装adb 谷歌的安卓平台下载ADB软件包进行安装:链接 安装好后adb.exe 一般保存在C:\Users\用户名xx\AppData\Local\Android\Sdk\platform-tools 需要将其加到系统环境变量中: -- 以win11为例,系统-系统信息-高级系统设置-环境变量 -- 新建AndroidHome=C:\Users\用户名xx\AppData\Local\Android\Sdk -- Path-新建:%AndroidHome%\platform-tools # 第二步:手机连接电脑 华为Mate30手机为例: - 开启开发者模式:设置-关于手机-点击“版本号”多次直到提示“您已进入开发者模式” - 打开USB调试:设置-系统与更新-开发人员选项-USB调试-选择USB配置(多媒体传输) # 第三步:文件传输到手机 - 将所需文件下载到D:\Downloads\litedemo - 10.png # 测试图像 - clas_system # 可执行文件 - config_pplcnet.txt # config文件 - label_list.txt # 标签映射文件 - libpaddle_light_api_shared.so - pplcnet.nb # 模型权重文件 - 在D:\Downloads\litedemo下打开终端: adb devices # 显示设备 adb shell ls # 查看手机系统目录 # 使用adb push命令将文件夹中所有文件传输到手机上: adb shell mkdir -p /data/local/tmp/arm_cpu/ adb push clas_system /data/local/tmp/arm_cpu/ adb push config_pplcnet.txt /data/local/tmp/arm_cpu/ adb push label_list.txt /data/local/tmp/arm_cpu/ adb push libpaddle_light_api_shared.so /data/local/tmp/arm_cpu/ adb push pplcnet.nb /data/local/tmp/arm_cpu/ adb shell chmod +x /data/local/tmp/arm_cpu//clas_system # 需要加可执行权限 adb shell 'export LD_LIBRARY_PATH=/data/local/tmp/arm_cpu/; /data/local/tmp/arm_cpu/clas_system /data/local/tmp/arm_cpu/config_pplcnet.txt /data/local/tmp/arm_cpu/10.png'
预测成功,看到如下结果:
测试成功后,可将文件夹删除adb shell rm -r /data/local/tmp/arm_cpu/
总结
本文通过一个计算机视觉领域中最基础的任务之图像分类,带领大家熟悉百度Paddle深度学习框架中的各种组件。案例选自智慧农业场景,有现实场景应用需求,本系列的后续文章将沿袭这一思路,继续分享更多采用Paddle深度学习框架服务更多产业应用的案例。
- 模型预测
- 模型评估
- 开启训练
- 修改配置文件:参考ppcls/configs/ImageNet/PPLCNetV2/PPLCNetV2_base.yaml
- 下载预训练权重:让模型参数有个好的初始化