1. 简述
本次的任务是针对树叶的图片数据集进行分类。约24694个图片。185个类别。本次是用的是PaddleX的AI快速开发套件和安卓demo部署。
2. 数据预处理
2.1. 导入Paddle
# 导入paddle
# 设定GPU,如果使用的是基础版本,可以忽略这个代码块
import paddle
import cv2
import os
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
paddle.device.set_device("gpu:0")
import warnings
warnings.filterwarnings("ignore")
2.2. 解压处理数据集
# 解压数据集到loadta中
!unzip data/data148551/leaves-classification-cupai.zip -d data/loaddata/
# 显示数据集的结构
!tree data/loaddata/
# 图片抽样
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
%matplotlib inline
# 读取数据集中一个文件夹的路径
file_dir = 'data/loaddata/images/images/'
# 设立列表存储图片名
filesum = []
# 读取图片名
for root, dirs, files in os.walk(file_dir):
filesum.append(files)
filesum = filesum[0]
# 打印图片名看看效果符不符合预期
# print(filesum)
# 定义画布大小
plt.figure(figsize=(8, 8))
# 循环读取图片并显示
for i in range(1,5):
plt.subplot(2,2,i)
plt.title(filesum[i])
image = file_dir+filesum[i]
# print(f">>>{image}")
plt.imshow(cv2.imread(image,1))
plt.tight_layout()
plt.show()
# 读取训练集的数据表
traincsv = pd.read_csv("data/loaddata/train.csv")
traincsv
# 提取标签数据,并把标签数据存入集合中,计算出标签的种类一共多少
traincsv['label']
# 这里用到了集合的概念
labelname = set(traincsv['label'])
len(labelname)
# 新建一个空文件夹来存放处理后的数据集
os.mkdir('data/loaddata/processedimage')
接下来是使用程序来生成文件夹,文件夹名称是标签名,这是 PaddleX 的必要步骤
# 以标签名来创建文件夹
import os
for i in labelname:
os.mkdir('data/loaddata/processedimage/'+i)
# 将对应标签的图片放入对应的文件夹
import shutil
for i in range(traincsv.shape[0]):
filename = traincsv.iloc[i,0].replace("images/","")
# print(filename)
src = 'data/loaddata/images/images/'
des = 'data/loaddata/processedimage/'+traincsv.iloc[i,1] +'/'
shutil.copy(os.path.join(src, filename), os.path.join(des))
3. 安装PaddleX
# 使用pip安装方式安装2.1.0版本PaddleX:
!pip install paddlex==2.1.0 -i https://mirror.baidu.com/pypi/simple
4. 划分数据集
# 在模型进行训练时,我们需要划分训练集,验证集和测试集
# 因此需要对如上数据进行划分,直接使用paddlex命令即可将数据集随机划分成70%训练集,20%验证集和10%测试集
# 划分好的数据集会额外生成labels.txt, train_list.txt, val_list.txt, test_list.txt四个文件,之后可直接进行训练。
!paddlex --split_dataset --format ImageNet --dataset_dir data/loaddata/processedimage/ --val_value 0.2 --test_value 0.1
5. 特征工程¶
特征工程是将原始数据转化成更好的表达问题本质的特征的过程,使得将这些特征运用到预测模型中能提高对不可见数据的模型预测精度。
# 在训练和验证过程中,数据的处理
# https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/apis/transforms/transforms.md#4
from paddlex import transforms as T
train_transforms = T.Compose([
#图片自由裁剪
T.MixupImage(),#对图像进行 mixup 操作
T.RandomExpand(),#随机扩张图像
T.RandomDistort(),#以一定的概率对图像进行随机像素内容变换,可包括亮度、对比度、饱和度、色相角度、通道顺序的调整
T.Resize(target_size=400),#随机选取目标尺寸调整图像大小
T.RandomCrop(crop_size=224),#随机裁剪图像
T.Resize(255, interp='LINEAR', keep_ratio=False),#随机选取目标尺寸调整图像大小。
T.RandomHorizontalFlip(prob=0.7),#以一定的概率对图像进行随机水平翻转
#T.RandomVerticalFlip(prob=0.7),#以一定的概率对图像进行随机垂直翻转
T.RandomBlur(prob=0.1),#以一定的概率对图像进行高斯模糊
T.Normalize()])#对图像进行标准化。
eval_transforms = T.Compose([
T.ResizeByShort(short_size=256),#以一定的概率对图像进行随机像素内容变换,可包括亮度、对比度、饱和度、色相角度、通道顺序的调整
T.Normalize()#对图像进行标准化。
])
import paddlex as pdx
# 定义数据集,pdx.datasets.ImageNet表示读取ImageNet格式的分类数据集:
train_dataset = pdx.datasets.ImageNet(
data_dir='data/loaddata/processedimage/',
file_list='data/loaddata/processedimage/train_list.txt',
label_list='data/loaddata/processedimage/labels.txt',
transforms=train_transforms,
shuffle=True)
eval_dataset = pdx.datasets.ImageNet(
data_dir='data/loaddata/processedimage/',
file_list='data/loaddata/processedimage/val_list.txt',
label_list='data/loaddata/processedimage/labels.txt',
transforms=eval_transforms)
6. 设计模型并训练
# 使用百度基于蒸馏方法得到的预训练模型,模型结构与原来一致,但精度更高。
# num_classes 是类别数,需要自定义,默认是1000
num_classes = len(train_dataset.labels)
model = pdx.cls.ResNet200_vd(num_classes=num_classes)
model.train(num_epochs=200,
train_dataset=train_dataset,
train_batch_size=64,
eval_dataset=eval_dataset,
save_interval_epochs=2,
learning_rate = 0.01,
save_dir='output/ResNet200_vd',
#训练的输出保存在output/ResNet200_vd
use_vdl=True)
#use_vdl=True表示可以启动visualdl并查看可视化的指标变化情况。
# 读取测试集的数据
testcsv = pd.read_csv("data/loaddata/test.csv")
testcsv
7. 模型预测
# 模型预测
import paddlex as pdx
import paddle
ans = pd.DataFrame(columns=['image','label'])
# 调用GPU
paddle.device.set_device('gpu:0')
# 加载模型
model = pdx.load_model('output/ResNet200_vd/best_model')
# 设定图片地址
path = 'data/loaddata/images/'
anspre = []
for i in range(testcsv.shape[0]):
src = path + testcsv.iloc[i]
result = model.predict(src)
print(result)
result = result[0]
print(result)
result = result[0]
print(result)
#print(result['category'])
anspre.append(testcsv.iloc[i,0])
anspre.append(result['category'])
print(anspre)
ans.loc[i] = pd.Series({'image': testcsv.iloc[i,0], 'label': result['category']})
anspre = []
#print(f"i == {i}")
# 将结果保存为csv文件
ans.to_csv("answer.csv",index=0)
8. 模型处理
# 输出模型文件
!paddlex --export_inference --model_dir=./output/ResNet200_vd/best_model --save_dir=work/inference_model
# 安装paddlelite
!pip install paddlelite
# 导出模型,转换模型为.nb文件
!paddle_lite_opt \
--model_file=work/inference_model/inference_model/model.pdmodel \
--param_file=work/inference_model/inference_model/model.pdiparams \
--optimize_out=work/inference_model/model \
--optimize_out_type=naive_buffer \
--valid_targets=arm
9. 安卓部署
需要修改的是0.jpg | model.nb | labels.txt这三个后缀的文件
在图片中已经标注出来
(记得新建个文件夹存放自己的.nb模型文件)
接下来修改上图中圈圈出来的string.xml文件
将红色的框框行为修改为自己的文件名字或者路径即可
10. 结果展示
一切完成后,运行调试,输出如下:
<img src="https://ai-studio-static-online.cdn.bcebos.com/74cef75131a64550a86e4c5187e3c2b625b97cb6d760484988d3998b91770f20" width="30%">
11. 总结
本次的AI达人创造营第三期让我受益良多
本来会以为安卓的部署会有很多困难
但是看了直播课程会发现
飞桨的开发套件已经内置了可以使用的 Demo
基本上可以说是手把手教学
尽管本人对安卓的语法和架构的理解比较浅
但还是有惊无险完成了安卓端的部署
感谢飞桨的平台课程
使得我能够成功完成本次部署的项目
然而,本项目还有很多不足:
-
安卓端的 Demo 布局还可以进一步优化改善
-
模型预测的提示文字还可以进一步修改
这些都可以进一步进行完善