基于PaddleClas的101种食品分类(含安卓部署)

基于PaddleClas的101种食品分类,通过Paddle-Lite实现安卓部署

在这里插入图片描述

项目参考了@iterhui的“基于PaddleClas2.2的从零到落地安卓部署的奥特曼分类实战

paddleclas官方文档:

https://paddleclas.readthedocs.io/zh_CN/latest/

配套安卓项目地址

https://github.com/yingchenxing/PaddleClas-based-Food-Classification

演示app下载

https://github.com/yingchenxing/PaddleClas-based-Food-Classification/releases/download/demo/app-debug.apk

效果展示

项目数据集介绍

来源:

https://data.vision.ee.ethz.ch/cvl/datasets_extra/food-101/

AI Studio:

https://aistudio.baidu.com/aistudio/datasetdetail/106502

我们引入了 101 个食物类别的具有挑战性的数据集,包含 101,000 张图像。对于每个类,提供 250 张人工审核的测试图像以及 750 张训练图像。训练图像没有被故意清理,因此仍然包含一定量的噪声。这主要以强烈的颜色和有时错误的标签的形式出现。所有图像都重新调整为最大边长为 512 像素。 在该数据集中,包含了生活中常见的各种食物类别的多张图像,分别为它们在不同环境和光照条件下的图像,帮助模型在训练后能适应各种环境下的识别需求,提高识别的准确率。

项目背景:

食品分类,旨在对图片中食品进行种类划分,对图像中的食品进行标识。在食品安全,个人营养科学摄入等领域有较高的使用价值。随着我国经济的不断发展,居民生活水平不断提高,越来越多的食品出现在人们的餐桌上,吃不饱的问题虽然被解决,但是营养饮食与食品安全越来越受到人们的关注。在目前的食品安全行业与营养行业中,对食品进行划分和分析消耗了大量的人力,而食品分类可以帮助营养规划或营养师们更好地对摄入进行分配。利用人工智能技术,对多来源,多场景的食品图像进行充分的训练,打造简洁,实用的模型与算法,对食品种类进行可靠快速的划分。

项目创新点:

对于食品分类来说,最大的特点是食品种类复杂,对特征的划分有更高的要求,同时还要避免不同环境光下的干扰。对于数据集来说,食品种类图片分布不均衡容易导致部分种类食品识别率较低, 本项目需要对食品图片进行分类,标注出最有可能的种类。同时,本项目还通过PaddleLite实现了在安卓端的部署。

运行环境

套件版本号
paddlepaddle2.3.1
PaddleLite2.11
PaddleClas2.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

https://github.com/PaddlePaddle/Paddle-Lite-Demo/tree/master/PaddleLite-android-demo/image_classification_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. 成功运行

从手机相册导入:

在这里插入图片描述

项目总结

  1. 模型对某些相似类型食物的识别准确度有待提高
  2. 安卓项目暂时找不到稳定的模拟器安装,只能直接用手机或其他安卓设备测试
  3. 调参:测试集和训练集的文件路径,分类数,图片处理大小,epoch

此文仅为搬运,原作链接:https://aistudio.baidu.com/aistudio/projectdetail/4344470?channel=0&channelType=0&shared=1

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常抱歉,我的回答有误。以下是一个基于PaddleClas的图像分类模型训练代码示例: ```python import paddle import paddle.vision.transforms as T from paddle.vision.datasets import ImageNet from paddle.static import InputSpec from paddle.metric import Accuracy from paddle.optimizer import Momentum from paddle.regularizer import L2Decay from paddleslim.nas.ofa import OFA # 定义数据增强 train_transforms = T.Compose([ T.Resize(256), T.RandomCrop(224), T.RandomHorizontalFlip(), T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) val_transforms = T.Compose([ T.Resize(256), T.CenterCrop(224), T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) # 加载训练数据集和测试数据集 train_dataset = ImageNet(mode='train', transform=train_transforms) val_dataset = ImageNet(mode='val', transform=val_transforms) # 定义模型 model = OFA('ofa_mbv3_d234_e346_k357_w1.0', pretrained=True) model = paddle.Model(model, inputs=[InputSpec([None, 3, 224, 224], 'float32', 'image')], labels=[InputSpec([None, 1], 'int64', 'label')]) # 定义优化器和学习率衰减策略 optimizer = Momentum(learning_rate=0.1, momentum=0.9, weight_decay=L2Decay(1e-4)) lr_scheduler = paddle.optimizer.lr.StepDecay(learning_rate=0.1, step_size=30, gamma=0.1) # 定义损失函数 criterion = paddle.nn.CrossEntropyLoss() # 开始训练 model.prepare(optimizer, criterion, Accuracy()) model.fit(train_dataset, val_dataset, epochs=90, batch_size=256, save_dir='ofa_mbv3_d234_e346_k357_w1.0', save_freq=5, log_freq=10, lr_scheduler=lr_scheduler) ``` 这个示例代码基于PaddleClas的OFA模块,可以使用不同的网络结构、参数数量和计算复杂度进行训练,以适应不同的硬件和应用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值