基于PaddleClas2.2的奥特曼识别,从数据训练到利用PaddleLite2.9框架将模型部署到树莓派4b 64位(调用python api进行图片视频流识别)

news/2024/12/2 16:08:43/

网上PaddleClass2.2文章很少,都是2.1,但是2.2和2.1的配置还是有些区别的,而且看了网上很多关于paddle lite树莓派相关教程都是修改cc文件,然后./run.sh。但是没有直接调用python api的教程,更有甚至利用python使用os.system('./run.sh')进行调用,实在难受。因此有了这篇文章来记录一下。

本项目主要是基于PaddleClas2.2的奥特曼识别,从数据训练到利用PaddleLite2.9框架将模型部署到树莓派4b 64位,然后在树莓派上利用paddlelite框架的python api进行模型转换和图片&视频流对奥特曼的识别。


目录

1.数据处理

2.模型训练

3.模型评估

4.模型转换

5.树莓派部署


1.数据处理

我们利用百度的aistudio白嫖算力进行数据训练。

首先是数据解压处理

# 数据解压
!unzip -oq /home/aistudio/data/data104203/aoteman.zip

aoteman文件夹结构如下

aoteman
├── dijia
│   ├── 001.jpg
│   ├── 002.jpg
│   ├── 003.jpg
│   ├── ······
├── jieke
│   ├── 001.jpg
│   ├── 002.jpg
│   ├── 003.jpg
│   ├── ······
├── saiwen
│   ├── 001.jpg
│   ├── 002.jpg
│   ├── 003.jpg
│   ├── ······
├── tailuo
│   ├── 001.jpg
│   ├── 002.jpg
│   ├── 003.jpg
│   ├── ······
├──predict_demo.jpg

由于代码执行警告太多很烦,我也先去掉

import warnings
warnings.filterwarnings("ignore")

数据集划分是个很烦的事,之前我也是自己def了n个函数划分然后写入txt,很麻烦,小白甚至觉得训练都没数据处理烦,这里我推荐jikuai库,可以一键划分生成txt,我们先安装一下。

!pip install jikuai -q

 那么接下来我们就开始git paddleclas了 ,并选择2.2分支

!git clone https://gitee.com/paddlepaddle/PaddleClas.git -b release/2.2

然后利用jiekuai进行数据划分

%cd ~/
from jikuai.dataset import Dataset
dataset = Dataset("aoteman") # 参数为数据集所在的位置,是分类目录的上一级目录
dataset.paddleclastxt(0.8) # 生成训练集和测试集列表,参数为两者划分的比例值。
!ls
# 2280348.ipynb  aoteman	data  eval.txt	PaddleClas  train.txt  work

我们把数据移到PaddleClas/dataset里,方便打包

!mv eval.txt aoteman/
!mv train.txt aoteman/
!mv aoteman PaddleClas/dataset/

2.模型训练

接下来是最重要的tran前配置了,不得不说PaddleClas比PaddleDetection配置要方便多了,全在一个yaml里

我们对 PaddleClas/ppcls/configs/quick_start/new_user/ShuffleNetV2_x0_25.yaml 进行修改设置

主要是以下几点:分类数、训练和验证的路径、图像尺寸、数据预处理、训练和预测的num_workers: 0才可以在aistudio跑通。

# global configs
Global:checkpoints: null# 预训练模型加载,这里不用了pretrained_model: null # 模型保存地址output_dir: ./output/ # 没有gpu就用cpudevice: gpu # 每几个轮次保存一次save_interval: 1eval_during_train: True# 每几个轮次验证一次eval_interval: 1# 训练600轮次epochs: 600# 每10步打印print_batch_step: 10# 可视化,这里不开启use_visualdl: False# 预测模型导出地址image_shape: [3, 224, 224]save_inference_dir: ./inference# 模型结构
Arch:name: ShuffleNetV2_x0_25# 类别class_num: 4# 训练/评估过程的损失函数配置 
Loss:Train:- CELoss:weight: 1.0Eval:- CELoss:weight: 1.0Optimizer:name: Momentummomentum: 0.9lr:name: Cosinelearning_rate: 0.0125warmup_epoch: 5regularizer:name: 'L2'coeff: 0.00001# 用于训练和评估的数据加载配置
DataLoader:Train:dataset:name: ImageNetDataset# 文件根目录 因为train.txt格式是“aoteman/tailuo/072.jpg 3” 以便导入image_root: ./dataset# train划分地址cls_label_path: ./dataset/aoteman/train.txt# 数据预处理transform_ops:- DecodeImage:to_rgb: Truechannel_first: False- RandCropImage:size: 224- RandFlipImage:flip_code: 1- NormalizeImage:scale: 1.0/255.0mean: [0.485, 0.456, 0.406]std: [0.229, 0.224, 0.225]order: ''sampler:name: DistributedBatchSampler# 每一步16个数据加载batch_size: 16drop_last: Falseshuffle: Trueloader:num_workers: 0 # 这里一定要0才可以跑通aistudiouse_shared_memory: TrueEval:dataset: name: ImageNetDatasetimage_root: ./datasetcls_label_path: ./dataset/aoteman/eval.txttransform_ops:- DecodeImage:to_rgb: Truechannel_first: False- ResizeImage:resize_short: 256- CropImage:size: 224- NormalizeImage:scale: 1.0/255.0mean: [0.485, 0.456, 0.406]std: [0.229, 0.224, 0.225]order: ''sampler:name: DistributedBatchSamplerbatch_size: 64drop_last: Falseshuffle: Falseloader:num_workers: 0use_shared_memory: TrueInfer:infer_imgs: ./dataset/aoteman/predict_demo.jpgbatch_size: 10transforms:- DecodeImage:to_rgb: Truechannel_first: False- ResizeImage:resize_short: 256- CropImage:size: 224- NormalizeImage:scale: 1.0/255.0mean: [0.485, 0.456, 0.406]std: [0.229, 0.224, 0.225]order: ''- ToCHWImage:PostProcess:name: Topk# 输出的可能性最高的前topk个topk: 4# 标签文件 需要自己新建文件class_id_map_file: ./dataset/aoteman/labels.txt
Metric:Train:- TopkAcc:topk: [1, 4]Eval:- TopkAcc:topk: [1, 4]

自己建个标签文件 ./dataset/label_list.txt

0 迪迦奥特曼  
1 杰克奥特曼  
2 赛文奥特曼  
3 泰罗奥特曼

配置搞定,那么接下来开始训练吧~

# 采用GPU训练
!export CUDA_VISIBLE_DEVICES=0
%cd ~/PaddleClas/
!python tools/train.py \-c ./ppcls/configs/quick_start/new_user/ShuffleNetV2_x0_25.yaml

训练结果一窥究竟

[2021/08/13 18:01:49] root INFO: [Train][Epoch 596/600][Iter: 0/28]lr: 0.00001, CELoss: 0.03720, loss: 0.03720, top1: 1.00000, top4: 1.00000, batch_cost: 0.30420s, reader_cost: 0.25090, ips: 52.59725 images/sec, eta: 0:00:42
[2021/08/13 18:01:51] root INFO: [Train][Epoch 596/600][Iter: 10/28]lr: 0.00001, CELoss: 0.13251, loss: 0.13251, top1: 0.96023, top4: 1.00000, batch_cost: 0.22338s, reader_cost: 0.17151, ips: 71.62723 images/sec, eta: 0:00:29
[2021/08/13 18:01:53] root INFO: [Train][Epoch 596/600][Iter: 20/28]lr: 0.00001, CELoss: 0.12071, loss: 0.12071, top1: 0.96131, top4: 1.00000, batch_cost: 0.21830s, reader_cost: 0.16640, ips: 73.29514 images/sec, eta: 0:00:26
[2021/08/13 18:01:55] root INFO: [Train][Epoch 596/600][Avg]CELoss: 0.11507, loss: 0.11507, top1: 0.96591, top4: 1.00000
[2021/08/13 18:01:56] root INFO: [Eval][Epoch 596][Iter: 0/2]CELoss: 0.30446, loss: 0.30446, top1: 0.92188, top4: 1.00000, batch_cost: 1.02158s, reader_cost: 0.99066, ips: 62.64828 images/sec
[2021/08/13 18:01:56] root INFO: [Eval][Epoch 596][Avg]CELoss: 0.31860, loss: 0.31860, top1: 0.90909, top4: 1.00000
[2021/08/13 18:01:56] root INFO: [Eval][Epoch 596][best metric: 0.9454545497894287]
[2021/08/13 18:01:56] root INFO: Already save model in ./output/ShuffleNetV2_x0_25/epoch_596
[2021/08/13 18:01:56] root INFO: Already save model in ./output/ShuffleNetV2_x0_25/latest

训练600epoch,基本上top1能稳定90-96%以上了。大家可以试下加载预训练模型,举个例子。

python3 tools/train.py \-c ./ppcls/configs/quick_start/MobileNetV3_large_x1_0.yaml \-o Arch.pretrained=True \-o Global.device=gpu

其中Arch.pretrained设置为True表示加载ImageNet的预训练模型,此外,Arch.pretrained也可以指定具体的模型权重文件的地址,使用时需要换成自己的预训练模型权重文件的路径。

3.模型评估

对我们模型评估一下 ,有90以上了,可以用了。

%cd ~/PaddleClas
!python3 tools/eval.py \-c ./ppcls/configs/quick_start/new_user/ShuffleNetV2_x0_25.yaml \-o Global.pretrained_model=output/ShuffleNetV2_x0_25/latest
[2021/08/14 10:30:57] root INFO: [Eval][Epoch 0][Iter: 0/2]CELoss: 0.31628, loss: 0.31628, top1: 0.92188, top4: 1.00000, batch_cost: 1.16294s, reader_cost: 1.12821, ips: 55.03274 images/sec
[2021/08/14 10:30:57] root INFO: [Eval][Epoch 0][Avg]CELoss: 0.33670, loss: 0.33670, top1: 0.90909, top4: 1.00000

我们用我们的模型来验证一下

!python3 tools/infer.py \-c ./ppcls/configs/quick_start/new_user/ShuffleNetV2_x0_25.yaml \-o Infer.infer_imgs=dataset/aoteman/predict_demo.jpg \-o Global.pretrained_model=output/ShuffleNetV2_x0_25/latest
[{'class_ids': [0, 1, 3, 2], 'scores': [1.0, 0.0, 0.0, 0.0], 'file_name': 'dataset/aoteman/predict_demo.jpg', 'label_names': ['迪迦奥特曼  ', '杰克奥特曼  ', '泰罗奥特曼', '赛文奥特曼  ']}]

验证推定100%是迪迦奥特曼,我们看下是不是迪迦奥特曼。 果然是哈~

4.模型转换

最后要把模型导出inference模型,为什么又要导出新格式模型呢,原来模型不是可以用了吗?因为原来模型是包含正向和反向传播的,而我们部署上线是不需要反向传播的,因此我们导出预测专用的inference模型。

# 导出inference模型
!python3 tools/export_model.py \-c ./ppcls/configs/quick_start/new_user/ShuffleNetV2_x0_25.yaml \-o Global.pretrained_model=./output/ShuffleNetV2_x0_25/latest

模型导出到了我们.yaml里写的 PaddleClas/inference文件夹里里,我们将他下载上传到树莓派里,我们开始下一阶段。

5.树莓派部署

首先进行树莓派PaddleLite2.9源码编译,这大家也可以参考官方文档。

https://paddle-lite.readthedocs.io/zh/latest/source_compile/compile_linux.html

 我们先写个inference模型转nb模型的python代码

# https://paddlelite.paddlepaddle.org.cn/api_reference/python_api/opt.html
# 引用Paddlelite预测库
from paddlelite.lite import *# 1. 创建opt实例
opt=Opt()
# 2. 指定输入模型地址
# 非combined形式
#opt.set_model_dir("./mobilenet_v1")
# conmbined形式,具体模型和参数名称,请根据实际修改
opt.set_model_file("./aoteman_inference/inference.pdmodel")
opt.set_param_file("./aoteman_inference/inference.pdiparams")
# 3. 指定转化类型: arm、x86、opencl、npu
opt.set_valid_places("arm")
# 4. 指定模型转化类型: naive_buffer、protobuf
opt.set_model_type("naive_buffer")
# 5. 动态离线量化
opt.set_quant_model(True)
opt.set_quant_type("QUANT_INT8")
# 6. 输出模型地址
opt.set_optimize_out("aoteman_model")
# 7. 执行模型优化
opt.run()

 生成aoteman_model.nb模型,这样才可以被paddlelite调用。

然后我们建个predict.py利用python api进行模型调用和推断

from paddlelite.lite import *
import cv2
import numpy as np
import sys
import time
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw# 加载模型
def create_predictor(model_dir):config = MobileConfig()config.set_model_from_file(model_dir)predictor = create_paddle_predictor(config)return predictor    #图像归一化处理
def process_img(image, input_image_size):origin = imageimg = origin.resize(input_image_size, Image.BILINEAR)resized_img = img.copy()if img.mode != 'RGB':img = img.convert('RGB')img = np.array(img).astype('float32').transpose((2, 0, 1))  # HWC to CHWimg -= 127.5img *= 0.007843img = img[np.newaxis, :]return origin,img# 预测
def predict(image, predictor, input_image_size):#输入数据处理input_tensor = predictor.get_input(0)input_tensor.resize([1, 3, input_image_size[0], input_image_size[1]])image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA))origin, img = process_img(image, input_image_size)image_data = np.array(img).flatten().tolist()input_tensor.set_float_data(image_data)#执行预测predictor.run()#获取输出output_tensor = predictor.get_output(0)print("output_tensor.float_data()[:] : ", output_tensor.float_data()[:])res = output_tensor.float_data()[:]return res# 展示结果
def post_res(label_dict, res):print(max(res))target_index = res.index(max(res))print("结果是:" + "   " + label_dict[target_index])if __name__ == '__main__':# 初始定义label_dict = {0:"dijia", 1:"jieke", 2:"saiwen", 3:"tailuo"}image = "./saiwen2.jpg"model_dir = "./trans/aoteman_model.nb"image_size = (224, 224)# 初始化predictor = create_predictor(model_dir)# 读入图片image = cv2.imread(image)# 预测res = predict(image, predictor, image_size)# 显示结果post_res(label_dict, res)cv2.imshow("image", image)cv2.waitKey()

 

网上随便找的赛文奥特曼被推断出来了~

 除了照片识别还不满足,我们利用摄像头视频流进行识别,建了个predict_camera.py如下

from paddlelite.lite import *
import cv2
import numpy as np
import sys
import time
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw# 加载模型
def create_predictor(model_dir):config = MobileConfig()config.set_model_from_file(model_dir)predictor = create_paddle_predictor(config)return predictor    #图像归一化处理
def process_img(image, input_image_size):origin = imageimg = origin.resize(input_image_size, Image.BILINEAR)resized_img = img.copy()if img.mode != 'RGB':img = img.convert('RGB')img = np.array(img).astype('float32').transpose((2, 0, 1))  # HWC to CHWimg -= 127.5img *= 0.007843img = img[np.newaxis, :]return origin,img# 预测
def predict(image, predictor, input_image_size):#输入数据处理input_tensor = predictor.get_input(0)input_tensor.resize([1, 3, input_image_size[0], input_image_size[1]])image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA))origin, img = process_img(image, input_image_size)image_data = np.array(img).flatten().tolist()input_tensor.set_float_data(image_data)#执行预测predictor.run()#获取输出output_tensor = predictor.get_output(0)# print("output_tensor.float_data()[:] : ", output_tensor.float_data()[:])res = output_tensor.float_data()[:]return res# 展示结果
def post_res(label_dict, res):# print(max(res))target_index = res.index(max(res))# print("结果是:" + "   " + label_dict[target_index], "准确率为:",  max(res))print(max(res))return max(res), label_dict[target_index]
if __name__ == '__main__':# 初始定义label_dict = {0:"dijia", 1:"jieke", 2:"saiwen", 3:"tailuo"}model_dir = "./trans/aoteman_model.nb"image_size = (224, 224)# 初始化predictor = create_predictor(model_dir)cap = cv2.VideoCapture(0)while True:ret, frame = cap.read()# 预测print('Predict Start')time_start=time.time()res = predict(frame, predictor, image_size)confidence, label_result = post_res(label_dict, res)fps = 1/(time.time()-time_start)# 显示结果post_res(label_dict, res)if confidence > 0.5:cv2.putText(frame, '{}'.format(label_result), (20, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)cv2.putText(frame, '{:.2f}'.format(confidence), (20, 100), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)cv2.putText(frame, 'fps:{:.2f}'.format(fps), (20, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)cv2.imshow("frame", frame)if cv2.waitKey(1) & 0xFF == ord('q'):cv2.imwrite('out.png', frame)print("save one image done!")breakprint('Predict End')cap.release()cv2.destroyAllWindows()

迪迦奥特曼被识别出来了!

需要图像数据或者opencv paddlelite编译需求,甚至镜像需要请私聊。

如下配置镜像,并开启jupyter开机自启,插件已经装全。
    OpenCV 4.5.1
    ncnn 20210124
    MNN 1.1.0
    Paddle-Lite 2.9
    TensorFlow-Lite 2.4.1
    TensorFLow 2.4.1
    TensorFlow Addons 0.13.0-dev
    Pytorch 1.8.0
    TorchVision 0.9.0


http://www.ppmy.cn/news/667315.html

相关文章

ARM Ubuntu内核更新记录

1,系统版本说明:ARM 鲲鹏920 cat /etc/lsb-release DISTRIB_IDUbuntu DISTRIB_RELEASE18.04 DISTRIB_CODENAMEbionic DISTRIB_DESCRIPTION"Ubuntu 18.04.5 LTS" 2, 将source.list中的deb-src打开 # 默认注释了源码镜像以提高 apt…

python添加图片水印_python 批量添加图片水印

python程序,用来批量添加图片水印。输入一个文件夹、水印位置(左下角、底部中间、右下角)、用户名(用户名是中文的),批量给文件夹里所有的jpg和png图片在指定位置添加水印。 水印内容是:用户名 拍摄时间 拍摄地点。其中用户名是入参&#xff…

两小时快速入门 TypeScript 基础(二)面向对象

个人简介 👀个人主页: 前端杂货铺 🙋‍♂️学习方向: 主攻前端方向,也会涉及到服务端(Node.js 等) 📃个人状态: 2023届本科毕业生,已拿多个前端 offer&#x…

u盘ntfs和fat32哪个好 把u盘改成ntfs有什么影响

u盘在日常生活中的使用频率很高,许多用户在选购u盘时很少会注意到u盘格式,但u盘的格式对u盘的使用有很大影响。u盘格式有很多,常见的有ntfs和fa32,u盘ntfs和fat32哪个好?这要看u盘的使用场景。把u盘改成ntfs有什么影响…

ps中给图层新建文件夹

快捷键:CtrlG 或者点击菜单中–图层–新建–组

PS_为新建图层添加背景色

方法1&#xff1a; 将 <设置背景色> 调整为想要的背景颜色选中相应的图层CtrlBackspace 方法2&#xff1a; 将 <设置前景色> 调整为想要的背景颜色选中相应的图层选中<油漆桶工具>&#xff0c;点击图片

PS 父图层与子图层

创建一半空白的页面&#xff0c;写上一段话&#xff0c;例如&#xff1a;OneStopWeb。在它的上方新建一个图层。 然后“按着Alt,把鼠标放在两个图层之间&#xff0c;出现一个向下的箭头和矩形&#xff0c;点击左键”&#xff0c;就出现如图这种状态。 最后&#xff0c;你在这个…

关于PS新建(PS如何新建)

最近在自学PS&#xff0c;整理一些PS学习的笔记 对于如何新建呢&#xff1f;PS页面进去左上角有一个文件&#xff0c;点击文件--选择新建就好了。 点击后页面会弹出一个页面&#xff0c;对新建图层的尺寸&#xff0c;分辨率等按自己的需求进行更改就好了&#xff0c;具体如下…