Are you sure you want to delete this task? Once this task is deleted, it cannot be recovered.
肖雄 f83fba9caf | 1 year ago | |
---|---|---|
PaddleClas | 1 year ago | |
README.md | 1 year ago | |
demo_video.mp4 | 1 year ago |
城市垃圾分类最早始于 1995 年上海市,2000 年,建设部在北京、南京、杭州、厦门等城市进行垃圾分类试点,将垃圾分类收集分为废纸、塑料、金属以及有毒有害废电池等。经过 20 多年来的发展,垃圾分类模式已经作了数次调整,把垃圾分为:有机垃圾、无机垃圾、有毒有害垃圾;干垃圾、湿垃圾、有害垃圾;废玻璃、可燃垃圾以及有害垃圾;可堆肥垃圾、有害垃圾、其他垃圾等等。
2020年11月,住建部等12部门联合印发了《关于进一步推进生活垃圾分类工作的若干意见》,明确了到2025年,46个重点城市要基本建立配套完善的生活垃圾分类法律法规制度体系,地级以上城市因地制宜基本建立生活垃圾分类投放、收集、运输、处理系统,居民普遍形成生活垃圾分类习惯。足以体现国家对生活垃圾分类工作的高度重视。
“十三五”期间,国家在无害化处理城镇生活垃圾的设施建设期间,投资总额累计达到了2518.4亿元。其中,投资建设无害化处理设施的资金累计达到了1699.3亿元。国家投资金额巨大,市场潜力巨大。
本项目主要是从垃圾产生的源头来进行分类处理,也就是对生活中随处可见的普通垃圾桶进行智能化改造升级,从根本上解决人工垃圾分类在人力,物力,财力上的巨大投入,以及对环境造成的巨大污染问题。
# 克隆Sports_Game_tracker仓库
git clone https://openi.pcl.ac.cn/xiaoxiong/Intelligent_garbage_can.git
# 打开本地的notebook环境
飞桨图像识别套件PaddleClas是飞桨为工业界和学术界所准备的一个图像识别和图像分类任务的工具集,助力使用者训练出更好的视觉模型和应用落地。
下面我以手动环境配置为例,进行讲解
# 安装gpu版本的paddlepaddle
!python3 -m pip install paddlepaddle-gpu -i https://mirror.baidu.com/pypi/simple
# 安装paddleclas-2.4.2成功后,重启一下内核
!pip install paddleclas
# 运行结果
# Successfully installed faiss-cpu-1.7.1.post2 opencv-python-4.4.0.46 paddleclas-2.4.2
# Note: you may need to restart the kernel to use updated packages.
由于访问 GitHub 网速较慢,可以从 Gitee 下载,命令如下:
!git clone https://gitee.com/paddlepaddle/PaddleClas.git -b release/2.4
PaddleClas 的 Python 依赖库在 requirements.txt 中给出,可通过如下命令安装:
%cd PaddleClas
%pip install --upgrade -r requirements.txt -i https://mirror.baidu.com/pypi/simple
模型预测有两种方式:命令行方式与python代码模式
!paddleclas --model_name=PPLCNet_x1_0 --infer_imgs="docs/images/inference_deployment/whl_demo.jpg"
# 预测结果如下
# class_ids: [8, 7, 86, 81, 85],
# scores: [0.91347, 0.03779, 0.0036, 0.00117, 0.00112],
# label_names: ['hen', 'cock', 'partridge', 'ptarmigan', 'quail'],
# filename: docs/images/inference_deployment/whl_demo.jpg
# Predict complete!
from paddleclas import PaddleClas
# result为可迭代对象,因此需要使用 next() 函数或 for 循环对其迭代调用。
# 每次调用将以 batch_size 为单位进行一次预测,并返回预测结果。
clas = PaddleClas(model_name='PPLCNet_x1_0')
infer_imgs='docs/images/deployment/whl_demo.jpg'
result=clas.predict(infer_imgs)
print(next(result))
# 预测结果如下
# [
# { 'class_ids': [8, 7, 86, 81, 85],
# 'scores': [0.91347, 0.03779, 0.0036, 0.00117, 0.00112],
# 'label_names': ['hen', 'cock', 'partridge', 'ptarmigan', 'quail'],
# 'filename': 'docs/images/inference_deployment/whl_demo.jpg'
# }
# ]
PaddleClas 使用 txt 格式文件指定训练集和测试集,train_list.txt 和 val_list.txt 分别为训练集和验证集的标签文件,其格式说明可以参考PaddleClas分类数据集格式说明
其中 train_list.txt 和 val_list.txt 的格式形如:
# 每一行采用"空格"分隔图像路径与标注
# 下面是 train_list.txt 中的格式样例:
taoci/IMG_8886.JPG 4
tudou/IMG_8936.JPG 5
yinliaoping/IMG_9065.JPG 9
yilaguan/IMG_7987.JPG 8
pingguo/IMG_8726.JPG 2
# 下面是 val_list.txt 中的格式样例:
pingguo/IMG_8754.JPG 2
pingguo/IMG_8795.JPG 2
tudou/IMG_8377.JPG 5
xiangjiao/IMG_8998.JPG 6
pingguo/IMG_7814.JPG 2
下载数据集:https://openi.pcl.ac.cn/attachments/8929acc6-3faa-4df0-93d7-1884ebd4b530?type=0
# 将数据集解压至PaddleClas/dataset/目录下
!unzip 垃圾十分类.zip -d PaddleClas/dataset/
cd ../../
在 ppcls/configs/ImageNet/PPLCNet/PPLCNet_x1_0.yaml 中提供了 PPLCNet_x1_0 训练配置,可以通过如下脚本启动训练。
但在启动训练之前需要对PPLCNet_x1_0.yaml的参数进行修改
Global:
pretrained_model: https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/legendary_models/PPLCNet_x1_0_pretrained.pdparams
save_interval: 1 # 模型保存间隔
eval_during_train: True # 启动验证集
eval_interval: 1 # 每训练完一轮就进行验证
epochs: 10 # 总训练轮数
print_batch_step: 10 # 每迭代10个iters打印一次训练信息
class_num: 10 # 类别数
learning_rate: 0.00625000 # 学习率
batch_size: 16 # 训练批次
Train:
dataset:
name: ImageNetDataset
image_root: ./dataset/
cls_label_path: ./dataset/train_list.txt
Eval:
dataset:
name: ImageNetDataset
image_root: ./dataset/
cls_label_path: ./dataset/val_list.txt
Infer:
infer_imgs: ./dataset/taoci/IMG_7923.JPG
...
PostProcess:
class_id_map_file: ./dataset/labels.txt
# 将CUDA设置为单卡
!export CUDA_VISIBLE_DEVICES=0
!python3 -m paddle.distributed.launch \
--gpus="0" \
tools/train.py \
-c ppcls/configs/ImageNet/PPLCNet/PPLCNet_x1_0.yaml
# 训练结果非常nice,在epoch=2时,验证集上的top1和top5的准确率就已经达到了1
# [2022/07/19 18:57:40] [Eval][Epoch 2][Iter: 0/13] CELoss: 0.09414, loss: 0.09414, top1: 1.00000, top5: 1.00000, batch_cost: 9.11237s, reader_cost: 9.08816, ips: 1.75586 images/sec
# [2022/07/19 18:57:56] [Eval][Epoch 2][Iter: 10/13]CELoss: 0.06553, loss: 0.06553, top1: 1.00000, top5: 1.00000, batch_cost: 1.35222s, reader_cost: 1.31854, ips: 11.83241 images/sec
# [2022/07/19 18:57:58] [Eval][Epoch 2] [Avg]CELoss: 0.05911, loss: 0.05911, top1: 1.00000, top5: 1.00000
训练好模型之后,可以通过以下命令实现对模型指标的评估。
!python3 tools/eval.py \
-c ppcls/configs/ImageNet/PPLCNet/PPLCNet_x1_0.yaml \
-o Global.pretrained_model=output/PPLCNet_x1_0/best_model
# 验证结果
# [2022/07/19 19:44:10] [Eval][Epoch 0][Iter: 0/13] CELoss: 0.09414, loss: 0.09414, top1: 1.00000, top5: 1.00000, batch_cost: 9.49708s, reader_cost: 9.39857, ips: 1.68473 images/sec
# [2022/07/19 19:44:27] [Eval][Epoch 0][Iter: 10/13]CELoss: 0.06553, loss: 0.06553, top1: 1.00000, top5: 1.00000, batch_cost: 1.36988s, reader_cost: 1.34440, ips: 11.67983 images/sec
# [2022/07/19 19:44:29] [Eval][Epoch 0] [Avg]CELoss: 0.05911, loss: 0.05911, top1: 1.00000, top5: 1.00000
模型训练完成之后,可以加载训练得到的预训练模型,进行模型预测。在模型库的 tools/infer.py 中提供了完整的示例,只需执行下述命令即可完成模型预测:
!python3 tools/infer.py \
-c ppcls/configs/ImageNet/PPLCNet/PPLCNet_x1_0.yaml \
-o Global.pretrained_model=output/PPLCNet_x1_0/best_model
# 预测结果评分高达0.95
# [
# {
# 'class_ids': [4, 9, 6, 7, 5],
# 'scores': [0.95325, 0.01007, 0.00961, 0.00652, 0.00556],
# 'file_name': './dataset/taoci/IMG_7923.JPG',
# 'label_names': []
# }
# ]
以下是将权重和模型转换的脚本,执行该脚本可以得到对应的 inference 模型:
!python3 tools/export_model.py \
-c ppcls/configs/ImageNet/PPLCNet/PPLCNet_x1_0.yaml \
-o Global.pretrained_model=output/PPLCNet_x1_0/best_model \
-o Global.save_inference_dir=deploy/models/PPLCNet_x1_0_infer
# 出现以下结果即为导出成功
# Export succeeded! The inference model exported has been saved in "deploy/models/PPLCNet_x1_0_infer".
执行完该脚本后会在 PaddleClas/deploy/models/ 下生成 PPLCNet_x1_0_infer 文件夹,models 文件夹下应有如下文件结构:
├── PPLCNet_x1_0_infer
│ ├── inference.pdiparams
│ ├── inference.pdiparams.info
│ └── inference.pdmodel
# 将PPLCNet_x1_0_infer文件夹压缩并上传至jetson nano
%cd deploy/models
!zip -r PPLCNet_x1_0_infer.zip PPLCNet_x1_0_infer/
# 将 data/data155466/垃圾检测.zip 上传至jetson nano
查看本机JetPack版本和python版本,在PaddleInference官网下载与本机版本对应的paddlepaddle即可
# 如下图,我的JetPack版本为4.6.2,python版本为3.6.9
sudo apt-cache show nvidia-jetpack
# 下载对应的PaddlePaddle到指定目录
wget -O /home/nvidia/paddlepaddle.whl "https://paddle-inference-lib.bj.bcebos.com/2.3.0/python/Jetson/jetpack4.6_gcc7.5/nano/paddlepaddle_gpu-2.3.0-cp36-cp36m-linux_aarch64.whl"
# 安装PaddlePaddle
pip install paddlepaddle.whl
# 下载Paddle-Inference-Demo,若网络不好可在本机下载完毕之后通过ssh连接传输到nano上
git clone https://github.com/PaddlePaddle/Paddle-Inference-Demo.git
# 将之前上传到nano上的inference模型压缩包:PPLCNet_x1_0_infer.zip,在nano上解压至/home/nvidia/Paddle-Inference-Demo/python/gpu/resnet50下
unzip PPLCNet_x1_0_infer.zip
# 对模型文件夹重命名
mv PPLCNet_x1_0_infer inference_model
# 将之前上传到nano上的数据集:垃圾检测.zip,移动到Paddle-Inference-Demo/python/gpu/resnet50并解压
mv 垃圾检测.zip Paddle-Inference-Demo/python/gpu/resnet50
unzip 垃圾检测.zip
# 对数据集重命名
mv 垃圾检测 dataset
# 将标签集labels.txt移动到Paddle-Inference-Demo/python/gpu/resnet50下
cd dataset
mv labels.txt ../
cd ../
nano infer_resnet.py
# 将下面的代码复制到infer_resnet.py中,ctrl+o保存,ctrl+x退出
import numpy as np
import argparse
import cv2
import sys
import time
from paddle.inference import Config
from paddle.inference import create_predictor
from paddle.inference import PrecisionType
from img_preprocess import preprocess
image_path = './dataset/test_list.txt'
labels_path = './labels.txt'
def init_predictor(args):
# 创建 config
if args.model_dir is not "":
config = Config(args.model_dir)
else:
config = Config(args.model_file, args.params_file)
config.disable_glog_info() # 去除 Paddle Inference 运行中的 LOG
config.enable_memory_optim() # 开启内存 / 显存复用,优化
config.enable_use_gpu(1000, 0) # 启用 GPU 进行预测
if args.run_mode == "gpu_fp16":
config.exp_enable_use_gpu_fp16()
elif args.run_mode == "trt_fp32":
config.enable_tensorrt_engine(workspace_size=1 << 30,
max_batch_size=1,
min_subgraph_size=5,
precision_mode=PrecisionType.Float32,
use_static=False,
use_calib_mode=False)
elif args.run_mode == "trt_fp16":
config.enable_tensorrt_engine(workspace_size=1 << 30,
max_batch_size=1,
min_subgraph_size=5,
precision_mode=PrecisionType.Half,
use_static=False,
use_calib_mode=False)
elif args.run_mode == "trt_int8":
config.enable_tensorrt_engine(workspace_size=1 << 30,
max_batch_size=1,
min_subgraph_size=5,
precision_mode=PrecisionType.Int8,
use_static=False,
use_calib_mode=True)
if args.use_dynamic_shape:
names = ["im_shape", "image", "scale_factor"]
min_input_shape = [[1, 2], [1, 3, 112, 112], [1, 2]]
max_input_shape = [[1, 2], [1, 3, 608, 608], [1, 2]]
opt_input_shape = [[1, 2], [1, 3, 608, 608], [1, 2]]
config.set_trt_dynamic_shape_info(
{names[0]: min_input_shape[0],
names[1]: min_input_shape[0],
names[2]: min_input_shape[0],
},
{names[0]: max_input_shape[1],
names[1]: max_input_shape[1],
names[2]: max_input_shape[1],
},
{names[0]: opt_input_shape[2],
names[1]: opt_input_shape[2],
names[2]: opt_input_shape[2],
}
)
predictor = create_predictor(config)
return predictor
def run(predictor, img):
# 复制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
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument(
"--model_file",
type=str,
default="",
help="模型文件名,当你的模型是一个组合模型时指定它。"
)
parser.add_argument(
"--params_file",
type=str,
default="",
help=
"参数文件名,当你的模型是一个组合模型时指定它。"
)
parser.add_argument(
"--model_dir",
type=str,
default="",
help=
"模型目录,如果你加载一个非组合模型,指定模型的目录。"
)
parser.add_argument(
"--run_mode",
type=str,
default="",
help=
"运行模式,包括:trt_fp32、trt_fp16、trt_int8和gpu_fp16。"
)
parser.add_argument("--use_dynamic_shape",
type=int,
default=0,
help="是否使用trt动态形状。")
return parser.parse_args()
# 加载标签集labels
def load_labels():
labels = []
fp_r = open(labels_path, 'r')
data = fp_r.readline()[:-1]
while data:
labels.append(data)
data = fp_r.readline()[:-1]
# print(labels)
fp_r.close()
return labels
if __name__ == '__main__':
args = parse_args()
pred = init_predictor(args) # 耗时6s
labels = load_labels()
if image_path[-3:] == 'txt':
img_list = []
f = open(image_path)
img = f.readline()[:-3]
while img:
img_list.append(img)
img = f.readline()[:-3]
f.close()
print("================== 预测报告 ===================")
for img_path in img_list:
img = cv2.imread('./dataset/' + img_path) # 耗时260ms
t1=time.time()
img = preprocess(img) # 耗时18ms
#img = np.ones((1, 3, 224, 224)).astype(np.float32)
if args.run_mode == "gpu_fp16":
img = img.astype(np.float16)
result = run(pred, [img]) # 耗时30ms
print("类别: ", labels[np.argmax(result[0][0])])
t2=time.time()
print('程序运行时间:%.2f毫秒' % ((t2 - t1)*1000))
nano run.sh
# 将下面的代码复制到run.sh中,ctrl+o保存,ctrl+x退出
python3 infer_resnet.py --model_file=./inference_model/model.pdmodel --params_file=./inference_model/model.pdiparams
# 运行预测脚本,对批量图片进行预测
python3 run.sh
# 播放软硬一体的实物视频
# 由于疫情封校原因,无法拿到网购的摄像头和底盘加固材料,所以视频中的投放过程摇摇晃晃,并且没有安装摄像头。
import IPython
IPython.display.Video('demo_video.mp4',width=400, height=200)
Your browser does not support the video
element.
项目整体的设计难点在于最初通过paddlelite来对树莓派进行部署,与nano相比树莓派的计算性能不仅弱爆了,而且编译部署上也是问题重重,折磨了我快一个多月。在从百度申请到nano的开发板之后,我几乎只用了一个下午就完成了模型的部署与功能的修改,而且在准确率不变的前提下,性能提升达到了91%,所以选用一个合适的开发板真的很重要。
在项目过程中总会遇到各种各样难以解决的问题,我认为持续不断的攻坚克难才是最终成功解决问题的关键,就比如我暑假留校,将两个月的时间都投入到了其中,每天学习,调试到深夜1,2点,虽然很苦很累,但当最终的项目成品正一步步呈现在自己眼前时,这一切努力就变得真的很值得!
关于这个项目其实还有很多不足地方,特别是硬件控制部分,选用二维舵机虽然结构比较简单,但一次却只能投放一个垃圾来进行分类,不能同时进行多个垃圾的分类。此外,该装置对于恶劣环境下,光干扰时,摄像头采集数据的稳定性也是个问题。以及垃圾桶的防水和供电问题也需要好好想想。总之,还有很长的路要走,我相信,当我下次再来参加创造营的活动时,会带来一个设计更加完美,功能更加完备的智能垃圾桶2.0
姓名:肖雄
学校:长江大学
专业:物联网工程大三在读
爱好:喜欢专研技术,对深度学习产业落地的前景十分看好,同时也在学习Spring全家桶,提高自己的软件设计能力。
主要方向:CV,软件开发
采用百度飞桨最新的图片分类模型PPLCNet,并在jetson nano上取得了单张图片分类约60ms,准确率100%的良好成绩
Markdown Python Text C++ Shell other
Dear OpenI User
Thank you for your continuous support to the Openl Qizhi Community AI Collaboration Platform. In order to protect your usage rights and ensure network security, we updated the Openl Qizhi Community AI Collaboration Platform Usage Agreement in January 2024. The updated agreement specifies that users are prohibited from using intranet penetration tools. After you click "Agree and continue", you can continue to use our services. Thank you for your cooperation and understanding.
For more agreement content, please refer to the《Openl Qizhi Community AI Collaboration Platform Usage Agreement》