基于PaddleClas的101种食品分类,通过Paddle-Lite实现安卓部署
项目参考了@iterhui的“基于PaddleClas2.2的从零到落地安卓部署的奥特曼分类实战”
paddleclas官方文档:
配套安卓项目地址
https://github.com/yingchenxing/PaddleClas-based-Food-Classification
演示app下载
效果展示
项目数据集介绍
来源:
AI Studio:
我们引入了 101 个食物类别的具有挑战性的数据集,包含 101,000 张图像。对于每个类,提供 250 张人工审核的测试图像以及 750 张训练图像。训练图像没有被故意清理,因此仍然包含一定量的噪声。这主要以强烈的颜色和有时错误的标签的形式出现。所有图像都重新调整为最大边长为 512 像素。 在该数据集中,包含了生活中常见的各种食物类别的多张图像,分别为它们在不同环境和光照条件下的图像,帮助模型在训练后能适应各种环境下的识别需求,提高识别的准确率。
项目背景:
食品分类,旨在对图片中食品进行种类划分,对图像中的食品进行标识。在食品安全,个人营养科学摄入等领域有较高的使用价值。随着我国经济的不断发展,居民生活水平不断提高,越来越多的食品出现在人们的餐桌上,吃不饱的问题虽然被解决,但是营养饮食与食品安全越来越受到人们的关注。在目前的食品安全行业与营养行业中,对食品进行划分和分析消耗了大量的人力,而食品分类可以帮助营养规划或营养师们更好地对摄入进行分配。利用人工智能技术,对多来源,多场景的食品图像进行充分的训练,打造简洁,实用的模型与算法,对食品种类进行可靠快速的划分。
项目创新点:
对于食品分类来说,最大的特点是食品种类复杂,对特征的划分有更高的要求,同时还要避免不同环境光下的干扰。对于数据集来说,食品种类图片分布不均衡容易导致部分种类食品识别率较低, 本项目需要对食品图片进行分类,标注出最有可能的种类。同时,本项目还通过PaddleLite实现了在安卓端的部署。
运行环境
套件 | 版本号 |
paddlepaddle | 2.3.1 |
PaddleLite | 2.11 |
PaddleClas | 2.4 |
安卓部署环境
Android Studio, 安卓手机(开启USB调试),下载到本地的官方demo
PaddleClas套件下载与环境准备
!git clone https://gitee.com/paddlepaddle/PaddleClas.git
%cd PaddleClas/
!pip install -r requirements.txt
# 解压数据集
%cd /home/aistudio/
!gzip -dfq /home/aistudio/data/data106502/food-101.tar.gz
!tar -xf /home/aistudio/data/data106502/food-101.tar
/home/aistudio
数据处理
将数据读取并打乱输出到train_list.txt,val_list.txt,按照4:1比例划分训练集和验证集。
import os
import random
Path = '/home/aistudio/food-101/images'
classes = os.listdir(Path)
classes=sorted(classes)
label=0
all_list=open("food-101/all_list.txt",'w')
train_list=open("food-101/train_list.txt",'w')
val_list=open("food-101/val_list.txt",'w')
for i in classes:
a=os.listdir(Path+'/'+i)
random.shuffle(a)
flag=0
for j in a:
j=i+'/'+j+' '+str(label)
all_list.write(str(j)+"\n")
if flag<800:
train_list.write(str(j)+"\n")
else:
val_list.write(str(j)+"\n")
flag+=1
label+=1
lines=[]
with open("food-101/train_list.txt", 'r') as infile:
for line in infile:
lines.append(line)
random.shuffle(lines)
with open("food-101/train_list.txt", 'w') as infile:
infile.truncate()
for line in lines:
infile.write(line)
lines=[]
with open("food-101/val_list.txt", 'r') as infile:
for line in infile:
lines.append(line)
random.shuffle(lines)
with open("food-101/val_list.txt", 'w') as infile:
infile.truncate()
for line in lines:
infile.write(line)
添加类别映射文件
# 将准备好的label列表放到数据集文件夹中,再将数据集移动到指定目录
%cd /home/aistudio/
!mv food_label_list.txt food-101/
!mv food-101/ PaddleClas/dataset/
/home/aistudio
使用paddleclas进行训练
模型选择
虽然移动端的模型体积小,速度快,但是牺牲了一定的精度。所以我们在这个项目中选择了ResNet_Vd。ResNet_Vd是ppcls框架主推的模型,经过了大量精度和速度上的优化。
修改配置文件
PaddleClas/ppcls/configs/quick_start/ResNet50_vd.yaml
关于配置的相关文档
https://paddleclas.readthedocs.io/zh_CN/latest/tutorials/config.html
# global configs
Global:
checkpoints: null
pretrained_model: null
output_dir: ./output/
device: gpu
save_interval: 5
eval_during_train: True
eval_interval: 5
epochs: 20
print_batch_step: 100
use_visualdl: False
# used for static mode and model export
image_shape: [3, 224, 224]
save_inference_dir: ./inference
# model architecture
Arch:
name: ResNet50_vd
class_num: 101
# 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.0125
warmup_epoch: 5
regularizer:
name: 'L2'
coeff: 0.00001
# data loader for train and eval
DataLoader:
Train:
dataset:
name: ImageNetDataset
image_root: ./dataset/food-101/images
cls_label_path: ./dataset/food-101/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/food-101/images
cls_label_path: ./dataset/food-101/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: dataset/food-101/images/apple_pie/1005649.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: ./dataset/food-101/food_label_list.txt
Metric:
Train:
- TopkAcc:
topk: [1, 3]
Eval:
- TopkAcc:
topk: [1, 3]
开始训练
!export CUDA_VISIBLE_DEVICES=0
%cd /home/aistudio/PaddleClas
!python tools/train.py \
-c ./ppcls/configs/quick_start/ResNet50_vd.yaml
模型预测
%cd /home/aistudio/PaddleClas
!python3 tools/infer.py \
-c ./ppcls/configs/quick_start/ResNet50_vd.yaml \
-o Infer.infer_imgs=dataset/food-101/images/pizza/340814.jpg \
-o Global.pretrained_model=output/ResNet50_vd/latest
输入图片:
预测结果:
‘class_ids’: [76, 71, 10, 97, 70], ‘scores’: [0.78302, 0.07978, 0.06082, 0.04327, 0.01048], ‘label_names’: [‘pizza’, ‘paella’, ‘bruschetta’, ‘takoyaki’, ‘pad_thai’]}]
预测76号概率最大,对应为pizza,也就是披萨的概率最大,预测准确
导出模型
!python3 tools/export_model.py \
-c ppcls/configs/quick_start/ResNet50_vd.yaml \
-o Global.pretrained_model=output/ResNet50_vd/latest
1. 安装paddlelite
!pip install paddlelite
2. 利用paddlelite将模型转为.nb文件
!paddle_lite_opt \
--model_file=inference/inference.pdmodel \
--param_file=inference/inference.pdiparams \
--optimize_out=./inference/ResNet50_vd \
--optimize_out_type=naive_buffer \
=./inference/ResNet50_vd \
--optimize_out_type=naive_buffer \
--valid_targets=arm
3. 下载.nb文件备用
路径 PaddleClas/inference/ResNet50_vd.nb
部署到安卓
1. 下载官方demo
解压后用Android Studio打开
更新gradle
2. 连接手机或模拟器
点击运行如果能看到下图则证明官方demo可用
3. 修改官方demo
3.1 在项目中的下列路径中新建文件夹ResNet50_vd
3.2 将之前导出的ResNet50_vd.nb改名为model.nb放到下列文件夹中
3.3 放入label标签文件
路径为PaddleClas/dataset/food-101/food_label_list.txt
直接下载,放在对应文件夹下即可
3.4 放入默认预测文件
3.5 修改对应配置
<string name="MODEL_PATH_DEFAULT">models/ResNet50_vd</string>
<string name="LABEL_PATH_DEFAULT">labels/food_label_list.txt</string>
<string name="IMAGE_PATH_DEFAULT">images/french_fries.jpg</string>
4. 成功运行
从手机相册导入:
项目总结
- 模型对某些相似类型食物的识别准确度有待提高
- 安卓项目暂时找不到稳定的模拟器安装,只能直接用手机或其他安卓设备测试
- 调参:测试集和训练集的文件路径,分类数,图片处理大小,epoch