基于PaddlePaddle2.0的蝴蝶图像识别分类——利用预训练残差网络ResNet101模型
分类资源来源如下:
https://aistudio.baidu.com/aistudio/education/group/info/11939

1. 蝴蝶识别分类任务概述

本项目将利用人工智能技术来对蝴蝶图像进行分类,需要能对蝴蝶的类别、属性进行细粒度的识别分类。相关研究工作者能够根据采集到的蝴蝶图片,快速识别图中蝴蝶的种类。期望能够有助于提升蝴蝶识别工作的效率和精度。

2. 创建项目和挂载数据

数据集都来源于网络公开数据(和鲸社区)。图片中所涉及的蝴蝶总共有9个属,20个物种,文件genus.txt中描述了9个属名,species.txt描述了20个物种名。

在创建项目时,可以为该项目挂载Butterfly20蝴蝶数据集,即便项目重启,该挂载的数据集也不会被自动清除。具体方法如下:首先采用notebook方式构建项目,项目创建框中的最下方有个数据集选项,选择“+添加数据集”。然后,弹出搜索框,在关键词栏目输入“bufferfly20”,便能够查询到该数据集。最后,选中该数据集,可以自动在项目中挂载该数据集了。

需要注意的是,每次重新打开该项目,data文件夹下除了挂载的数据集,其他文件都将被删除。

被挂载的数据集会自动出现在data目录之下,通常是压缩包的形式。在data/data63004目录,其中有两个压缩文件,分别是Butterfly20.zip和Butterfly20_test.zip。也可以利用下载功能把数据集下载到本地进行训练。

3. 初探蝴蝶数据集

看看蝴蝶图像数据长什么样子?

首先,解压缩数据。类以下几个步骤:

第一步,把当前路径转换到data目录,可以使用命令!cd data。在AI studio nootbook中可以使用Linux命令,需要在命令的最前面加上英文的感叹号(!)。用&&可以连接两个命令。用\号可以换行写代码。需要注意的是,每次重新打开该项目,data文件夹下除了挂载的数据集,其他文件都会被清空。因此,如果把数据保存在data目录中,每次重新启动项目时,都需要解压缩一下。如果想省事持久化保存,可以把数据保存在work目录下。

实际上,!加某命令的模式,等价于python中的get_ipython().system(‘某命令’)模式。

第二步,利用unzip命令,把压缩包解压到当前路径。unzip的-q参数代表执行时不显示任何信息。unzip的-o参数代表不必先询问用户,unzip执行后覆盖原有的文件。两个参数合起来,可以写为-qo。

第三步,用rm命令可以把一些文件夹给删掉,比如,__MACOSX文件夹

!cd data &&
unzip -qo data63004/Butterfly20_test.zip &&
unzip -qo data63004/Butterfly20.zip &&
rm -r __MACOSX

import matplotlib.pyplot as plt
import PIL.Image as Image
path1='/home/aistudio/data/Butterfly20/001.Atrophaneura_horishanus/006.jpg'
path2='/home/aistudio/data/Butterfly20/001.Atrophaneura_horishanus/150.jpg'
img1 = Image.open(path1)
plt.imshow(img1)          #根据数组绘制图像
plt.show()
img2 = Image.open(path2)
plt.imshow(img2)          #根据数组绘制图像
plt.show()               #显示图像

4. 准备数据

数据准备过程包括以下两个重点步骤:

一是建立样本数据读取路径与样本标签之间的关系。
二是构造读取器与数据预处理。可以写个自定义数据读取器,它继承于PaddlePaddle2.0的dataset类,在__getitem__方法中把自定义的预处理方法加载进去。

#以下代码用于建立样本数据读取路径与样本标签之间的关系
import os
import random
data_list = [] #用个列表保存每个样本的读取路径、标签
#由于属种名称本身是字符串,而输入模型的是数字。需要构造一个字典,把某个数字代表该属种名称。键是属种名称,值是整数。
label_list=[]
with open("/home/aistudio/data/species.txt") as f:for line in f:a,b = line.strip("\n").split(" ")label_list.append([b, int(a)-1])
label_dic = dict(label_list)
#获取Butterfly20目录下的所有子目录名称,保存进一个列表之中
class_list = os.listdir("/home/aistudio/data/Butterfly20")
class_list.remove('.DS_Store') #删掉列表中名为.DS_Store的元素,因为.DS_Store并没有样本。
for each in class_list:for f in os.listdir("/home/aistudio/data/Butterfly20/"+each):        data_list.append(["/home/aistudio/data/Butterfly20/"+each+'/'+f,label_dic[each]])
#按文件顺序读取,可能造成很多属种图片存在序列相关,用random.shuffle方法把样本顺序彻底打乱。
random.shuffle(data_list)
#打印前十个,可以看出data_list列表中的每个元素是[样本读取路径, 样本标签]。
print(data_list[0:10])
#打印样本数量,一共有1866个样本。
print("样本数量是:{}".format(len(data_list)))

打印结果

下面代码中用到了数据增强,包括olorJitter,RandomHorizontalFlip,RandomVerticalFlip,RandomRotation
API的使用可以参考paddle文档
paddl文档 paddle.vision.transforms

#以下代码用于构造读取器与数据预处理
#首先需要导入相关的模块
import paddle
from paddle.vision.transforms import Compose, ColorJitter, Resize,Transpose, Normalize
import cv2
import numpy as np
from PIL import Image
from paddle.io import Dataset
#自定义的数据预处理函数,输入原始图像,输出处理后的图像,可以借用paddle.vision.transforms的数据处理功能
def preprocess(img):if(random.random()>0.3):transform1 =ColorJitter(0.1, 0.4, 0.4, 0.1)img = transform1(img)if(random.random()>0.6):transform1 =RandomRotation(40)img = transform1(img)    transform = Compose([Resize(size=(224, 224)), #把数据长宽像素调成224*224RandomHorizontalFlip(0.4),RandomVerticalFlip(0.1),Normalize(mean=[127.5, 127.5, 127.5], std=[127.5, 127.5, 127.5], data_format='HWC'), #标准化Transpose(), #原始数据形状维度是HWC格式,经过Transpose,转换为CHW格式])img = transform(img).astype("float32")return img
#自定义数据读取器
class Reader(Dataset):def __init__(self, data, is_val=False):super().__init__()#在初始化阶段,把数据集划分训练集和测试集。由于在读取前样本已经被打乱顺序,取20%的样本作为测试集,80%的样本作为训练集。self.samples = data[-int(len(data)*0.2):] if is_val else data[:-int(len(data)*0.2)]def __getitem__(self, idx):#处理图像img_path = self.samples[idx][0] #得到某样本的路径img = Image.open(img_path)if img.mode != 'RGB':img = img.convert('RGB')img = preprocess(img) #数据预处理与数据增强#处理标签label = self.samples[idx][1] #得到某样本的标签label = np.array([label], dtype="int64") #把标签数据类型转成int64return img, labeldef __len__(self):#返回每个Epoch中图片数量return len(self.samples)#生成训练数据集实例
train_dataset = Reader(data_list, is_val=False)
#生成测试数据集实例
eval_dataset = Reader(data_list, is_val=True)
#打印一个训练样本
#print(train_dataset[1136][0])
print(train_dataset[1136][0].shape)
print(train_dataset[1136][1])

打印如下

5. 建立模型

为了提升探索速度,建议首先选用比较成熟的基础模型,看看基础模型所能够达到的准确度。之后再试试模型融合,准确度是否有提升。最后可以试试自己独创模型。

为简便,这里直接采用101层的残差网络ResNet,并且采用预训练模式。为什么要采用预训练模型呢?因为通常模型参数采用随机初始化,而预训练模型参数初始值是一个比较确定的值。这个参数初始值是经历了大量任务训练而得来的,比如用CIFAR图像识别任务来训练模型,得到的参数。虽然蝴蝶识别任务和CIFAR图像识别任务是不同的,但可能存在某些机器视觉上的共性。用预训练模型可能能够较快地得到比较好的准确度。

在PaddlePaddle2.0中,使用预训练模型只需要设定模型参数pretained=True。值得注意的是,预训练模型得出的结果类别是1000维度,要用个线性变换,把类别转化为20维度。

import paddle.nn.functional as F
#定义模型
class MyNet(paddle.nn.Layer):def __init__(self):super(MyNet,self).__init__()self.layer=paddle.vision.models.resnet152(pretrained=True)self.dropout=paddle.nn.Dropout(p=0.5)self.fc1 = paddle.nn.Linear(1000, 512)self.fc2 = paddle.nn.Linear(512, 20)#网络的前向计算过程def forward(self,x):x=self.layer(x)x=self.dropout(x)x=self.fc1(x)x=F.relu(x)x=self.fc2(x)return x

6. 应用高阶API训练模型

一是定义输入数据形状大小和数据类型。

二是实例化模型。如果要用高阶API,需要用Paddle.Model()对模型进行封装,如model = paddle.Model(model,inputs=input_define,labels=label_define)。

三是定义优化器。这个使用Adam优化器,学习率设置为0.0001,优化器中的学习率(learning_rate)参数很重要。要是训练过程中得到的准确率呈震荡状态,忽大忽小,可以试试进一步把学习率调低。

四是准备模型。这里用到高阶API,model.prepare()。

五是训练模型。这里用到高阶API,model.fit()。参数意义详见下述代码注释。

#定义输入
input_define = paddle.static.InputSpec(shape=[-1,3,224,224], dtype="float32", name="img")
label_define = paddle.static.InputSpec(shape=[-1,1], dtype="int64", name="label")#实例化网络对象并定义优化器等训练逻辑
model = MyNet()
model = paddle.Model(model,inputs=input_define,labels=label_define) #用Paddle.Model()对模型进行封装
optimizer = paddle.optimizer.Adam(learning_rate=0.0001, parameters=model.parameters())
#上述优化器中的学习率(learning_rate)参数很重要。要是训练过程中得到的准确率呈震荡状态,忽大忽小,可以试试进一步把学习率调低。model.prepare(optimizer=optimizer, #指定优化器loss=paddle.nn.CrossEntropyLoss(), #指定损失函数metrics=paddle.metric.Accuracy()) #指定评估方法callback = paddle.callbacks.VisualDL(log_dir='./log')model.fit(train_data=train_dataset,     #训练数据集eval_data=eval_dataset,         #测试数据集batch_size=64,                  #一个批次的样本数量epochs=50,                      #迭代轮次save_dir="/home/aistudio/lup", #把模型参数、优化器参数保存至自定义的文件夹save_freq=20,                    #设定每隔多少个epoch保存模型参数及优化器参数log_freq=100,                     #打印日志的频率verbose=1,                        # 日志展示模式shuffle=True,                     # 是否打乱数据集顺序callbacks=callback                # 回调函数使用)

训练效果如下

测试效果勉勉强强能够达到90%

7. 应用已经训练好的模型进行预测

如果是要参加建模比赛,通常赛事组织方会提供待预测的数据集,我们需要利用自己构建的模型,来对待预测数据集合中的数据标签进行预测。也就是说,我们其实并不知道到其真实标签是什么,只有比赛的组织方知道真实标签,我们的模型预测结果越接近真实结果,那么分数也就越高。

预测流程分为以下几个步骤:

一是构建数据读取器。因为预测数据集没有标签,该读取器写法和训练数据读取器不一样,建议重新写一个类,继承于Dataset基类。
二是实例化模型。如果要用高阶API,需要用Paddle.Model()对模型进行封装,如paddle.Model(MyNet(),inputs=input_define),由于是预测模型,所以仅设定输入数据格式就好了。
三是读取刚刚训练好的参数。这个保存在/home/aistudio/work目录之下,如果指定的是final则是最后一轮训练后的结果。可以指定其他轮次的结果,比如model.load(’/home/aistudio/work/30’),这里用到了高阶API,model.load()
四是准备模型。这里用到高阶API,model.prepare()。
五是读取待预测集合中的数据,利用已经训练好的模型进行预测。
六是结果保存。

class InferDataset(Dataset):def __init__(self, img_path=None):"""数据读取Reader(推理):param img_path: 推理单张图片"""super().__init__()if img_path:self.img_paths = [img_path]else:raise Exception("请指定需要预测对应图片路径")def __getitem__(self, index):# 获取图像路径img_path = self.img_paths[index]# 使用Pillow来读取图像数据并转成Numpy格式img = Image.open(img_path)if img.mode != 'RGB': img = img.convert('RGB') img = preprocess(img) #数据预处理--这里仅包括简单数据预处理,没有用到数据增强return imgdef __len__(self):return len(self.img_paths)#实例化推理模型
model = paddle.Model(MyNet(),inputs=input_define)
#读取刚刚训练好的参数
model.load('/home/aistudio/lup/final')
#准备模型
model.prepare()
#得到待预测数据集中每个图像的读取路径
infer_list=[]
with open("/home/aistudio/data/testpath.txt") as file_pred:for line in file_pred:infer_list.append("/home/aistudio/data/"+line.strip())#模型预测结果通常是个数,需要获得其对应的文字标签。这里需要建立一个字典。
def get_label_dict2():label_list2=[]with open("/home/aistudio/data/species.txt") as filess:for line in filess:a,b = line.strip("\n").split(" ")label_list2.append([int(a)-1, b])label_dic2 = dict(label_list2)return label_dic2
label_dict2 = get_label_dict2()
#print(label_dict2)
#利用训练好的模型进行预测
results=[]
for infer_path in infer_list:infer_data = InferDataset(infer_path)result = model.predict(test_data=infer_data)[0] #关键代码,实现预测功能result = paddle.to_tensor(result)result = np.argmax(result.numpy()) #获得最大值所在的序号results.append("{}".format(label_dict2[result])) #查找该序号所对应的标签名字
#把结果保存起来
with open("work/result.txt", "w") as f:for r in results:f.write("{}\n".format(r))

基于PaddlePaddle2.0的蝴蝶图像识别分类相关推荐

  1. 刚刚涉足神经网络,基于TensorFlow2.0以实现鸢尾花分类为例总结神经网络代码实现的几个步骤,附代码详细讲解

    前言 总体来看,一个简单的神经网络,在准备数据和参数定义后就已经被搭建起来了,这便是神经网络的骨架.我们后面补入的参数优化是为了让这个神经网络能够朝着我们希望的方向进行迭代,最后能获取到符合我们预期的 ...

  2. 基于PaddlePaddle2.0验证码端到端的识别

    验证码端到端的识别,是对<我的PaddlePaddle学习之路>笔记六--验证码端到端的识别 的升级,这篇文章是我18年初写的,基于当时的V2版本编写,现在有点过时了,突然想升级一下. 在 ...

  3. 【飞桨】【图像分类】【PaddlePaddle】蝴蝶图像识别

    基于PaddlePaddle2.0的蝴蝶图像识别分类--利用预训练残差网络ResNet101模型 1. 蝴蝶识别分类任务概述 人工智能技术的应用领域日趋广泛,新的智能应用层出不穷.本项目将利用人工智能 ...

  4. PaddlePaddle2.0搭建VGG-16模型实现蝴蝶分类

    PaddlePaddle2.0利用VGG-16预训练模型实现蝴蝶分类 本项目是百度AI Studio上图像分类课程的一个内容,之前使用ResNet101网络完成,现在用VGG-16网络实现同样的任务. ...

  5. 基于ERNIR3.0文本分类:(KUAKE-QIC)意图识别多分类(单标签)

    PaddleNLP基于ERNIR3.0文本分类以中医疗搜索检索词意图分类(KUAKE-QIC)为例[多分类(单标签)] 0.前言:文本分类任务介绍 文本分类任务是自然语言处理中最常见的任务,文本分类任 ...

  6. PaddleNLP基于ERNIR3.0文本分类以中医疗搜索检索词意图分类(KUAKE-QIC)为例【多分类(单标签)】

    相关项目链接: Paddlenlp之UIE模型实战实体抽取任务[打车数据.快递单] Paddlenlp之UIE分类模型[以情感倾向分析新闻分类为例]含智能标注方案) 应用实践:分类模型大集成者[Pad ...

  7. 基于Ernie-3.0 CAIL2019法研杯要素识别多标签分类任务

    相关项目: Paddlenlp之UIE模型实战实体抽取任务[打车数据.快递单] Paddlenlp之UIE分类模型[以情感倾向分析新闻分类为例]含智能标注方案) 应用实践:分类模型大集成者[Paddl ...

  8. 【Python深度学习】基于Tensorflow2.0构建CNN模型尝试分类音乐类型(二)

    前情提要 基于上文所说 基于Tensorflow2.0构建CNN模型尝试分类音乐类型(一) 我用tf2.0和Python3.7复现了一个基于CNN做音乐分类器.用余弦相似度评估距离的一个音乐推荐模型. ...

  9. PaddleNLP基于ERNIR3.0文本分类:WOS数据集为例(层次分类)

    相关项目链接: Paddlenlp之UIE模型实战实体抽取任务[打车数据.快递单] Paddlenlp之UIE分类模型[以情感倾向分析新闻分类为例]含智能标注方案) 应用实践:分类模型大集成者[Pad ...

最新文章

  1. C++中substr()函数用法详解
  2. Xamarin Essentials应用教程文件系统FileSystem
  3. 如何启用计算机超级账户,Windows7启用超级管理员账户的方法
  4. 给爸妈最硬核的春节礼物,走入百度大字版APP研发幕后
  5. 读郭老师推荐书籍--《原则》
  6. how is SAP OData metadata read from CDS view via SADL
  7. linux docker导入镜像,Docker镜像的导入和导出
  8. android 沉浸栏灰色,Android 沉浸栏实践——踩坑
  9. android studio管理依赖,Android Studio 中的 Gradle 依赖统一管理
  10. 收藏网站制作常用经典css.div.布局.设计实例打包下载
  11. Apache Log4j2远程代码执行漏洞攻击,华为云安全支持检测拦截
  12. 复选框改为html,根据复选框更改HTML值
  13. pay-spring-boot 开箱即用的Java支付模块,整合支付宝支付、微信支付
  14. win11系统正式版介绍
  15. P4778 Counting swaps (组合数学,打表推通项公式,OEIS)
  16. 电气工程cad实用教程电子版_电气工程CAD实用教程 pdf epub mobi txt 下载
  17. 基于单片机的超声波测距仪的设计
  18. P4684 [IOI2008]Fish(组合数学)
  19. iOS 画板 涂鸦 答题
  20. Carla中文版社区来了

热门文章

  1. 《大学“电路分析基础”课程实验合集.实验五》丨线性有源二端网络等效电路的研究
  2. 微信尝试刷掌支付;苹果 WWDC 将于 6 月 6 日开幕;Qt Creator 10 发布|极客头条
  3. Android设备与外接U盘实现数据读取操作
  4. 软件测试学习(基础篇)— —第5天:JS基础
  5. 获取王者荣耀皮肤所有高清图片-Python
  6. 无线wifi摄像头怎样可以远程监控
  7. Windows系统cmd命令+实用工具
  8. android16进制编辑器,16进制编辑器app
  9. 【12c】12c RMAN新特性之UNTIL AVAILABLE REDO--自动恢复到REDO终点的步骤简化
  10. 工作站Ubuntu16.04环境下安装nvidia显卡驱动